digitalmars.D - Bug w/structs and threads?
- Nate (17/45) Jun 05 2005 Hello,
- Nate (4/130) Jun 05 2005 Just to be a little more clear, if I place TimerElapsed(0,0); in the
- Andrew Fedoniouk (22/124) Jun 05 2005 I try following:
- Nate (9/173) Jun 05 2005 I've changed the code as suggested and the problem still remains. I
- Nate (6/132) Jun 06 2005 There has to be a bug here. I finally got this to work as it should and
- James Dunne (10/142) Jun 07 2005 Are you running a dual-processor PC? Are you running Windows or Linux?
- Sean Kelly (22/31) Jun 07 2005 And make sure you're using the same object for synchronization in each b...
Hello, I've been tearing my hair out on this little piece of code but now I am thinking there is nothing wrong with it! I have a struct that has 2 methods, one returns a rectangle (another struct) and the other changes the offset to know which rectangle to pull. Here is the odd part.. 95% of the time it works perfect. The other 5% of the time currentOffset is always 0 (or whatever initially set) for the GetSourceRectangle method. By using printf I see that in TimerElapsed (which is called from another thread) is setting the currentOffset properly 100% of the time. Its the other method that is not pulling the right value. printf says... running tile 66, offset is 1 (at top of timer elapsed) running tile 66, offset is now 2 (at end of timer elapsed) A anim 66 Returinging 0.000000 0.328125 (!!! its now at 2 this is 0 !!!) Any ideas on a work around? Here is a snip (attached is current code):Rectangle GetSourceRectangle(int offset) { /* This 90% of the time returns the proper * source rectangle from the array but for * 5-10 / 200 currentOffset is always the same * (0 default)! */ if(currentOffset + offset < sourceRects.length) { return sourceRects[this.currentOffset]; } else { return sourceRects[0]; } } void TimerElapsed(long l, long m) { /* This has workd 100% of the time */ if(CurrentTick() - lastTickUsed > (15 * animSpeed)) { if(currentOffset + 1 < sourceRects.length) this.currentOffset++; else this.currentOffset = 0; this.lastTickUsed = CurrentTick(); } }
Jun 05 2005
Just to be a little more clear, if I place TimerElapsed(0,0); in the GetSourceRectangle method all tiles work but they all should work without it. Nate wrote:Hello, I've been tearing my hair out on this little piece of code but now I am thinking there is nothing wrong with it! I have a struct that has 2 methods, one returns a rectangle (another struct) and the other changes the offset to know which rectangle to pull. Here is the odd part.. 95% of the time it works perfect. The other 5% of the time currentOffset is always 0 (or whatever initially set) for the GetSourceRectangle method. By using printf I see that in TimerElapsed (which is called from another thread) is setting the currentOffset properly 100% of the time. Its the other method that is not pulling the right value. printf says... running tile 66, offset is 1 (at top of timer elapsed) running tile 66, offset is now 2 (at end of timer elapsed) A anim 66 Returinging 0.000000 0.328125 (!!! its now at 2 this is 0 !!!) Any ideas on a work around? Here is a snip (attached is current code):Rectangle GetSourceRectangle(int offset) {> /* This 90% of the time returns the proper > * source rectangle from the array but for > * 5-10 / 200 currentOffset is always the same > * (0 default)! */if(currentOffset + offset < sourceRects.length) { return sourceRects[this.currentOffset]; } else { return sourceRects[0]; } } void TimerElapsed(long l, long m) {> /* This has workd 100% of the time */if(CurrentTick() - lastTickUsed > (15 * animSpeed)) { if(currentOffset + 1 < sourceRects.length) this.currentOffset++; else this.currentOffset = 0; this.lastTickUsed = CurrentTick(); } }------------------------------------------------------------------------ module Mapping.AnimatedTile; /* Copyright (C) 2005 Nate Plumm */ private import Drawing, Utilities.Tiles, Utilities.Timer; public struct AnimatedTile { private: Rectangle[] sourceRects; byte animSpeed; int frameCount = 0; long lastTickUsed = 0; int tileNumber = 0; int currentOffset = 0; public: bit useSecondSheet; static AnimatedTile opCall(int tileNumber, byte animSpeed, ushort[] animFrames, int frameCount) { AnimatedTile t; t.Setup(tileNumber, animSpeed, animFrames, frameCount); return t; } void Setup(int tileNumber, byte animSpeed, ushort[] animFrames, int frameCount) { this.tileNumber = tileNumber; this.animSpeed = animSpeed; this.frameCount = frameCount; sourceRects.length = frameCount; for(int i = 0; i < frameCount; i++) sourceRects[i] = Tiles.TileNumberToRectangle(animFrames[i], useSecondSheet); } Rectangle GetSourceRectangle(int offset) { if(this.currentOffset + offset < sourceRects.length) { return sourceRects[this.currentOffset]; } else { return sourceRects[0]; } } void TimerElapsed(long expectedTime, long realTime) // This is called from a different thread { if(CurrentTick() - lastTickUsed > (15 * animSpeed)) { if(this.currentOffset + 1 < sourceRects.length) this.currentOffset++; else this.currentOffset = 0; this.lastTickUsed = CurrentTick(); } } }
Jun 05 2005
I try following: 1) volatile int currentOffset = 0; // to exclude it from optimisations. I am not tested volatiles in D. But this variable must be volatile in C++ per your specification. 2) Your TimerElapsed must be changed to: void TimerElapsed(long expectedTime, long realTime) // This is called from a different thread { uint ct = CurrentTick(); if(ct - lastTickUsed > (15 * animSpeed)) { if(this.currentOffset + 1 < sourceRects.length) this.currentOffset++; else this.currentOffset = 0; this.lastTickUsed = ct; } } Andrew. "Nate" <plummn comdel.net> wrote in message news:d7v82t$1lpv$1 digitaldaemon.com...Hello, I've been tearing my hair out on this little piece of code but now I am thinking there is nothing wrong with it! I have a struct that has 2 methods, one returns a rectangle (another struct) and the other changes the offset to know which rectangle to pull. Here is the odd part.. 95% of the time it works perfect. The other 5% of the time currentOffset is always 0 (or whatever initially set) for the GetSourceRectangle method. By using printf I see that in TimerElapsed (which is called from another thread) is setting the currentOffset properly 100% of the time. Its the other method that is not pulling the right value. printf says... running tile 66, offset is 1 (at top of timer elapsed) running tile 66, offset is now 2 (at end of timer elapsed) A anim 66 Returinging 0.000000 0.328125 (!!! its now at 2 this is 0 !!!) Any ideas on a work around? Here is a snip (attached is current code):--------------------------------------------------------------------------------Rectangle GetSourceRectangle(int offset) { /* This 90% of the time returns the proper * source rectangle from the array but for * 5-10 / 200 currentOffset is always the same * (0 default)! */ if(currentOffset + offset < sourceRects.length) { return sourceRects[this.currentOffset]; } else { return sourceRects[0]; } } void TimerElapsed(long l, long m) { /* This has workd 100% of the time */ if(CurrentTick() - lastTickUsed > (15 * animSpeed)) { if(currentOffset + 1 < sourceRects.length) this.currentOffset++; else this.currentOffset = 0; this.lastTickUsed = CurrentTick(); } }module Mapping.AnimatedTile; /* Copyright (C) 2005 Nate Plumm */ private import Drawing, Utilities.Tiles, Utilities.Timer; public struct AnimatedTile { private: Rectangle[] sourceRects; byte animSpeed; int frameCount = 0; long lastTickUsed = 0; int tileNumber = 0; int currentOffset = 0; public: bit useSecondSheet; static AnimatedTile opCall(int tileNumber, byte animSpeed, ushort[] animFrames, int frameCount) { AnimatedTile t; t.Setup(tileNumber, animSpeed, animFrames, frameCount); return t; } void Setup(int tileNumber, byte animSpeed, ushort[] animFrames, int frameCount) { this.tileNumber = tileNumber; this.animSpeed = animSpeed; this.frameCount = frameCount; sourceRects.length = frameCount; for(int i = 0; i < frameCount; i++) sourceRects[i] = Tiles.TileNumberToRectangle(animFrames[i], useSecondSheet); } Rectangle GetSourceRectangle(int offset) { if(this.currentOffset + offset < sourceRects.length) { return sourceRects[this.currentOffset]; } else { return sourceRects[0]; } } void TimerElapsed(long expectedTime, long realTime) // This is called from a different thread { if(CurrentTick() - lastTickUsed > (15 * animSpeed)) { if(this.currentOffset + 1 < sourceRects.length) this.currentOffset++; else this.currentOffset = 0; this.lastTickUsed = CurrentTick(); } } }
Jun 05 2005
I've changed the code as suggested and the problem still remains. I tried putting volatile all over the place. 90% of the time it works and the other 10% currentOffset does not change that the other thread can see. It may be worth mentioning that this consistently happens on the same tiles every time. When calling timerelapsed from its own thread everything works. The tile at index 66 for example (dynamic array of a struct), this always happens. Andrew Fedoniouk wrote:I try following: 1) volatile int currentOffset = 0; // to exclude it from optimisations. I am not tested volatiles in D. But this variable must be volatile in C++ per your specification. 2) Your TimerElapsed must be changed to: void TimerElapsed(long expectedTime, long realTime) // This is called from a different thread { uint ct = CurrentTick(); if(ct - lastTickUsed > (15 * animSpeed)) { if(this.currentOffset + 1 < sourceRects.length) this.currentOffset++; else this.currentOffset = 0; this.lastTickUsed = ct; } } Andrew. "Nate" <plummn comdel.net> wrote in message news:d7v82t$1lpv$1 digitaldaemon.com...Hello, I've been tearing my hair out on this little piece of code but now I am thinking there is nothing wrong with it! I have a struct that has 2 methods, one returns a rectangle (another struct) and the other changes the offset to know which rectangle to pull. Here is the odd part.. 95% of the time it works perfect. The other 5% of the time currentOffset is always 0 (or whatever initially set) for the GetSourceRectangle method. By using printf I see that in TimerElapsed (which is called from another thread) is setting the currentOffset properly 100% of the time. Its the other method that is not pulling the right value. printf says... running tile 66, offset is 1 (at top of timer elapsed) running tile 66, offset is now 2 (at end of timer elapsed) A anim 66 Returinging 0.000000 0.328125 (!!! its now at 2 this is 0 !!!) Any ideas on a work around? Here is a snip (attached is current code):--------------------------------------------------------------------------------Rectangle GetSourceRectangle(int offset) { /* This 90% of the time returns the proper * source rectangle from the array but for * 5-10 / 200 currentOffset is always the same * (0 default)! */ if(currentOffset + offset < sourceRects.length) { return sourceRects[this.currentOffset]; } else { return sourceRects[0]; } } void TimerElapsed(long l, long m) { /* This has workd 100% of the time */ if(CurrentTick() - lastTickUsed > (15 * animSpeed)) { if(currentOffset + 1 < sourceRects.length) this.currentOffset++; else this.currentOffset = 0; this.lastTickUsed = CurrentTick(); } }module Mapping.AnimatedTile; /* Copyright (C) 2005 Nate Plumm */ private import Drawing, Utilities.Tiles, Utilities.Timer; public struct AnimatedTile { private: Rectangle[] sourceRects; byte animSpeed; int frameCount = 0; long lastTickUsed = 0; int tileNumber = 0; int currentOffset = 0; public: bit useSecondSheet; static AnimatedTile opCall(int tileNumber, byte animSpeed, ushort[] animFrames, int frameCount) { AnimatedTile t; t.Setup(tileNumber, animSpeed, animFrames, frameCount); return t; } void Setup(int tileNumber, byte animSpeed, ushort[] animFrames, int frameCount) { this.tileNumber = tileNumber; this.animSpeed = animSpeed; this.frameCount = frameCount; sourceRects.length = frameCount; for(int i = 0; i < frameCount; i++) sourceRects[i] = Tiles.TileNumberToRectangle(animFrames[i], useSecondSheet); } Rectangle GetSourceRectangle(int offset) { if(this.currentOffset + offset < sourceRects.length) { return sourceRects[this.currentOffset]; } else { return sourceRects[0]; } } void TimerElapsed(long expectedTime, long realTime) // This is called from a different thread { if(CurrentTick() - lastTickUsed > (15 * animSpeed)) { if(this.currentOffset + 1 < sourceRects.length) this.currentOffset++; else this.currentOffset = 0; this.lastTickUsed = CurrentTick(); } } }
Jun 05 2005
There has to be a bug here. I finally got this to work as it should and in order to do that I had to have a set array rather than a dynamic array of my struct. Should I submit this somewhere? This should work the same with either array type..no? Nate wrote:Hello, I've been tearing my hair out on this little piece of code but now I am thinking there is nothing wrong with it! I have a struct that has 2 methods, one returns a rectangle (another struct) and the other changes the offset to know which rectangle to pull. Here is the odd part.. 95% of the time it works perfect. The other 5% of the time currentOffset is always 0 (or whatever initially set) for the GetSourceRectangle method. By using printf I see that in TimerElapsed (which is called from another thread) is setting the currentOffset properly 100% of the time. Its the other method that is not pulling the right value. printf says... running tile 66, offset is 1 (at top of timer elapsed) running tile 66, offset is now 2 (at end of timer elapsed) A anim 66 Returinging 0.000000 0.328125 (!!! its now at 2 this is 0 !!!) Any ideas on a work around? Here is a snip (attached is current code):Rectangle GetSourceRectangle(int offset) {> /* This 90% of the time returns the proper > * source rectangle from the array but for > * 5-10 / 200 currentOffset is always the same > * (0 default)! */if(currentOffset + offset < sourceRects.length) { return sourceRects[this.currentOffset]; } else { return sourceRects[0]; } } void TimerElapsed(long l, long m) {> /* This has workd 100% of the time */if(CurrentTick() - lastTickUsed > (15 * animSpeed)) { if(currentOffset + 1 < sourceRects.length) this.currentOffset++; else this.currentOffset = 0; this.lastTickUsed = CurrentTick(); } }------------------------------------------------------------------------ module Mapping.AnimatedTile; /* Copyright (C) 2005 Nate Plumm */ private import Drawing, Utilities.Tiles, Utilities.Timer; public struct AnimatedTile { private: Rectangle[] sourceRects; byte animSpeed; int frameCount = 0; long lastTickUsed = 0; int tileNumber = 0; int currentOffset = 0; public: bit useSecondSheet; static AnimatedTile opCall(int tileNumber, byte animSpeed, ushort[] animFrames, int frameCount) { AnimatedTile t; t.Setup(tileNumber, animSpeed, animFrames, frameCount); return t; } void Setup(int tileNumber, byte animSpeed, ushort[] animFrames, int frameCount) { this.tileNumber = tileNumber; this.animSpeed = animSpeed; this.frameCount = frameCount; sourceRects.length = frameCount; for(int i = 0; i < frameCount; i++) sourceRects[i] = Tiles.TileNumberToRectangle(animFrames[i], useSecondSheet); } Rectangle GetSourceRectangle(int offset) { if(this.currentOffset + offset < sourceRects.length) { return sourceRects[this.currentOffset]; } else { return sourceRects[0]; } } void TimerElapsed(long expectedTime, long realTime) // This is called from a different thread { if(CurrentTick() - lastTickUsed > (15 * animSpeed)) { if(this.currentOffset + 1 < sourceRects.length) this.currentOffset++; else this.currentOffset = 0; this.lastTickUsed = CurrentTick(); } } }
Jun 06 2005
Are you running a dual-processor PC? Are you running Windows or Linux? I would first check that you're not trying to write to currentOffset at the same time you're reading from currentOffset in two separate threads. Use synchronized blocks around your accesses to currentOffset to see if this fixes your problem. Also, volatile keyword is a *statement* modifier in D, not a declaration modifier. This means that whenever you want to set the value of currentOffset, you do as such: volatile currentOffset = my_new_value; In article <d8366d$1hdm$1 digitaldaemon.com>, Nate says...There has to be a bug here. I finally got this to work as it should and in order to do that I had to have a set array rather than a dynamic array of my struct. Should I submit this somewhere? This should work the same with either array type..no? Nate wrote:Hello, I've been tearing my hair out on this little piece of code but now I am thinking there is nothing wrong with it! I have a struct that has 2 methods, one returns a rectangle (another struct) and the other changes the offset to know which rectangle to pull. Here is the odd part.. 95% of the time it works perfect. The other 5% of the time currentOffset is always 0 (or whatever initially set) for the GetSourceRectangle method. By using printf I see that in TimerElapsed (which is called from another thread) is setting the currentOffset properly 100% of the time. Its the other method that is not pulling the right value. printf says... running tile 66, offset is 1 (at top of timer elapsed) running tile 66, offset is now 2 (at end of timer elapsed) A anim 66 Returinging 0.000000 0.328125 (!!! its now at 2 this is 0 !!!) Any ideas on a work around? Here is a snip (attached is current code):Rectangle GetSourceRectangle(int offset) {> /* This 90% of the time returns the proper > * source rectangle from the array but for > * 5-10 / 200 currentOffset is always the same > * (0 default)! */if(currentOffset + offset < sourceRects.length) { return sourceRects[this.currentOffset]; } else { return sourceRects[0]; } } void TimerElapsed(long l, long m) {> /* This has workd 100% of the time */if(CurrentTick() - lastTickUsed > (15 * animSpeed)) { if(currentOffset + 1 < sourceRects.length) this.currentOffset++; else this.currentOffset = 0; this.lastTickUsed = CurrentTick(); } }------------------------------------------------------------------------ module Mapping.AnimatedTile; /* Copyright (C) 2005 Nate Plumm */ private import Drawing, Utilities.Tiles, Utilities.Timer; public struct AnimatedTile { private: Rectangle[] sourceRects; byte animSpeed; int frameCount = 0; long lastTickUsed = 0; int tileNumber = 0; int currentOffset = 0; public: bit useSecondSheet; static AnimatedTile opCall(int tileNumber, byte animSpeed, ushort[] animFrames, int frameCount) { AnimatedTile t; t.Setup(tileNumber, animSpeed, animFrames, frameCount); return t; } void Setup(int tileNumber, byte animSpeed, ushort[] animFrames, int frameCount) { this.tileNumber = tileNumber; this.animSpeed = animSpeed; this.frameCount = frameCount; sourceRects.length = frameCount; for(int i = 0; i < frameCount; i++) sourceRects[i] = Tiles.TileNumberToRectangle(animFrames[i], useSecondSheet); } Rectangle GetSourceRectangle(int offset) { if(this.currentOffset + offset < sourceRects.length) { return sourceRects[this.currentOffset]; } else { return sourceRects[0]; } } void TimerElapsed(long expectedTime, long realTime) // This is called from a different thread { if(CurrentTick() - lastTickUsed > (15 * animSpeed)) { if(this.currentOffset + 1 < sourceRects.length) this.currentOffset++; else this.currentOffset = 0; this.lastTickUsed = CurrentTick(); } } }
Jun 07 2005
In article <d844rs$2bkr$1 digitaldaemon.com>, James Dunne says...Are you running a dual-processor PC? Are you running Windows or Linux? I would first check that you're not trying to write to currentOffset at the same time you're reading from currentOffset in two separate threads. Use synchronized blocks around your accesses to currentOffset to see if this fixes your problem.And make sure you're using the same object for synchronization in each block that accesses the same thing. ie.Also, volatile keyword is a *statement* modifier in D, not a declaration modifier. This means that whenever you want to set the value of currentOffset, you do as such: volatile currentOffset = my_new_value;It's worth noting that all volatile does in D is ensure the compiler doesn't optimize around the volatile block--it does nothing to prevent CPU caching of writes. For that, you need a third-party library like Ben Hinkle's locks library--it has compareAndSet methods and such. (alternately, for the PC, use an asm block with the 'lock' instruction, as it is a full membar). Sean
Jun 07 2005