Thread overview | |||||||||
---|---|---|---|---|---|---|---|---|---|
|
June 05, 2005 Bug w/structs and threads? | ||||
---|---|---|---|---|
| ||||
Attachments: | 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(); > } > } |
June 05, 2005 Re: Bug w/structs and threads? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nate | 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();
> }
> }
> }
|
June 05, 2005 Re: Bug w/structs and threads? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nate | 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(); > } > } > } |
June 05, 2005 Re: Bug w/structs and threads? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrew Fedoniouk | 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();
>>}
>>}
>>}
>
>
>
|
June 07, 2005 Re: Bug w/structs and threads? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nate | 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();
> }
> }
> }
|
June 07, 2005 Re: Bug w/structs and threads? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nate | 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(); >> } >> } >> } |
June 07, 2005 Re: Bug w/structs and threads? | ||||
---|---|---|---|---|
| ||||
Posted in reply to James Dunne | 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. # Object glob = new Object(); # # void f1( MyStruct s ) { # synchronized( glob ) { # s.x = 5; # } # } # # void f2( MyStruct s ) { # synchronized( glob ) { # s.y = 10; # } # } >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 |
Copyright © 1999-2021 by the D Language Foundation