| Register | FAQ | Calendar | Search | Today's Posts | Mark Forums Read |
|
#11
| |||
| |||
| | To make changes to this is easy enough: | InterlockedExchange(ref _firstTime, 1); | | ... or I can use the InterlockedCompareExchange: | int oldValue = InterlockedCompareExchange(ref _firstTime, 1, 0); | | No problems here. | | ... but, if I just want to read the value, I CANNOT do: | | int myValue = _firstTime; | or | if (_fistTime==0) | | Doing these requires a memory barrier of some type (volatile variable, | monitor, etc) to have any degree of reliability. you can. The Interlocked write ensures this across all cpus and cache. Any thread reading the var after the Interlocked write will see the correct var so it is a memory barrier without a volatile modifier. All locks are ultimatley built on interlocked at the lowest level to get this behavior. So for reads, you can just go "if (var == 2){}". Naturally, this works for a single var. If you have multiple invariants you need to protect, you probabaly need a lock. |
|
#12
| |||
| |||
| William Stacey [C# MVP] <william.stacey> wrote: > | Doing these requires a memory barrier of some type (volatile variable, > | monitor, etc) to have any degree of reliability. > > you can. The Interlocked write ensures this across all cpus and cache. Any > thread reading the var after the Interlocked write will see the correct var > so it is a memory barrier without a volatile modifier. But surely that's only guaranteed if the read *actually* happens after the Interlocked write occurs. If the variable isn't volatile, there's nothing to stop the reading thread from having reordered the reads. For instance: int x=0, y=0; .... Thread 1: Interlocked.Increment (ref x, 1); Interlocked.Increment (ref y, 1); Thread 2: int a = x; int b = y; The JIT *could* reorder the reads of x and y in thread 2, such that you get a=0, b=1, despite the fact that x is incremented before y. That wouldn't be the case with volatile variables. At least, that's how I understand it. -- Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too |
|
#13
| |||
| |||
| William Stacey [C# MVP] <william.stacey> wrote: > | Doing these requires a memory barrier of some type (volatile variable, > | monitor, etc) to have any degree of reliability. > > you can. The Interlocked write ensures this across all cpus and cache. Any > thread reading the var after the Interlocked write will see the correct var > so it is a memory barrier without a volatile modifier. But surely that's only guaranteed if the read *actually* happens after the Interlocked write occurs. If the variable isn't volatile, there's nothing to stop the reading thread from having reordered the reads. For instance: int x=0, y=0; .... Thread 1: Interlocked.Increment (ref x, 1); Interlocked.Increment (ref y, 1); Thread 2: int a = x; int b = y; The JIT *could* reorder the reads of x and y in thread 2, such that you get a=0, b=1, despite the fact that x is incremented before y. That wouldn't be the case with volatile variables. At least, that's how I understand it. -- Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too |
|
#14
| |||
| |||
| | But surely that's only guaranteed if the read *actually* happens after | the Interlocked write occurs. If the variable isn't volatile, there's | nothing to stop the reading thread from having reordered the reads. For | instance: Hi Jon. Not sure I totally follow you here. If Interlocked x happens, a reader will never see x==0 (until it wraps). So a read on x or y is volatile using an interlocked. Naturally, in either method, a reader could read x and y after x was incremented, but before y was incremented because there is no lock here. But this is a different problem (i.e race). If we need both vars to be atomic in respect to each other and handled as an invariant "set", then we need a lock of some type protecting the set. As I said, maybe I am not following your intent and will slap my head. --wjs |
|
#15
| |||
| |||
| | But surely that's only guaranteed if the read *actually* happens after | the Interlocked write occurs. If the variable isn't volatile, there's | nothing to stop the reading thread from having reordered the reads. For | instance: Hi Jon. Not sure I totally follow you here. If Interlocked x happens, a reader will never see x==0 (until it wraps). So a read on x or y is volatile using an interlocked. Naturally, in either method, a reader could read x and y after x was incremented, but before y was incremented because there is no lock here. But this is a different problem (i.e race). If we need both vars to be atomic in respect to each other and handled as an invariant "set", then we need a lock of some type protecting the set. As I said, maybe I am not following your intent and will slap my head. --wjs |
|
#16
| |||
| |||
| William Stacey [C# MVP] <william.stacey> wrote: > | But surely that's only guaranteed if the read *actually* happens after > | the Interlocked write occurs. If the variable isn't volatile, there's > | nothing to stop the reading thread from having reordered the reads. For > | instance: > > Hi Jon. Not sure I totally follow you here. If Interlocked x happens, a > reader will never see x==0 (until it wraps). So a read on x or y is volatile > using an interlocked. Naturally, in either method, a reader could read x and > y after x was incremented, but before y was incremented because there is no > lock here. I still believe that it can read y before either of them are incremented, and x after both of them are incremented. There's nothing to stop the JIT from reordering the reads to read y before x, because they're not volatile. I wouldn't be surprised to learn that the interlocked operation makes sure that when it *does* try to read x and y, those values are really the latest ones, but I don't think there's any guarantee about the order of those reads unless at least one of them is volatile. (It's nearly midnight, so I can't be bothered to work out which it should be - y, I think.) I definitely *wasn't* talking about the atomicity of the two operations - just the ordering. -- Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too |
|
#17
| |||
| |||
| William Stacey [C# MVP] <william.stacey> wrote: > | But surely that's only guaranteed if the read *actually* happens after > | the Interlocked write occurs. If the variable isn't volatile, there's > | nothing to stop the reading thread from having reordered the reads. For > | instance: > > Hi Jon. Not sure I totally follow you here. If Interlocked x happens, a > reader will never see x==0 (until it wraps). So a read on x or y is volatile > using an interlocked. Naturally, in either method, a reader could read x and > y after x was incremented, but before y was incremented because there is no > lock here. I still believe that it can read y before either of them are incremented, and x after both of them are incremented. There's nothing to stop the JIT from reordering the reads to read y before x, because they're not volatile. I wouldn't be surprised to learn that the interlocked operation makes sure that when it *does* try to read x and y, those values are really the latest ones, but I don't think there's any guarantee about the order of those reads unless at least one of them is volatile. (It's nearly midnight, so I can't be bothered to work out which it should be - y, I think.) I definitely *wasn't* talking about the atomicity of the two operations - just the ordering. -- Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too |
|
#18
| |||
| |||
| So are you saying the JIT can reorder these two lines: int a = x; int b = y; Like so: int b = y; int a = x; ? tia -- William Stacey [C# MVP] "Jon Skeet [C# MVP]" <skeet@pobox.com> wrote in message news:MPG.20a86b07bb54e61e7d@msnews.microsoft.com.. . | William Stacey [C# MVP] <william.stacey> wrote: | > | But surely that's only guaranteed if the read *actually* happens after | > | the Interlocked write occurs. If the variable isn't volatile, there's | > | nothing to stop the reading thread from having reordered the reads. For | > | instance: | > | > Hi Jon. Not sure I totally follow you here. If Interlocked x happens, a | > reader will never see x==0 (until it wraps). So a read on x or y is volatile | > using an interlocked. Naturally, in either method, a reader could read x and | > y after x was incremented, but before y was incremented because there is no | > lock here. | | I still believe that it can read y before either of them are | incremented, and x after both of them are incremented. There's nothing | to stop the JIT from reordering the reads to read y before x, because | they're not volatile. I wouldn't be surprised to learn that the | interlocked operation makes sure that when it *does* try to read x and | y, those values are really the latest ones, but I don't think there's | any guarantee about the order of those reads unless at least one of | them is volatile. (It's nearly midnight, so I can't be bothered to work | out which it should be - y, I think.) | | I definitely *wasn't* talking about the atomicity of the two operations | - just the ordering. | | -- | Jon Skeet - <skeet@pobox.com> | http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet | If replying to the group, please do not mail me too |
|
#19
| |||
| |||
| So are you saying the JIT can reorder these two lines: int a = x; int b = y; Like so: int b = y; int a = x; ? tia -- William Stacey [C# MVP] "Jon Skeet [C# MVP]" <skeet@pobox.com> wrote in message news:MPG.20a86b07bb54e61e7d@msnews.microsoft.com.. . | William Stacey [C# MVP] <william.stacey> wrote: | > | But surely that's only guaranteed if the read *actually* happens after | > | the Interlocked write occurs. If the variable isn't volatile, there's | > | nothing to stop the reading thread from having reordered the reads. For | > | instance: | > | > Hi Jon. Not sure I totally follow you here. If Interlocked x happens, a | > reader will never see x==0 (until it wraps). So a read on x or y is volatile | > using an interlocked. Naturally, in either method, a reader could read x and | > y after x was incremented, but before y was incremented because there is no | > lock here. | | I still believe that it can read y before either of them are | incremented, and x after both of them are incremented. There's nothing | to stop the JIT from reordering the reads to read y before x, because | they're not volatile. I wouldn't be surprised to learn that the | interlocked operation makes sure that when it *does* try to read x and | y, those values are really the latest ones, but I don't think there's | any guarantee about the order of those reads unless at least one of | them is volatile. (It's nearly midnight, so I can't be bothered to work | out which it should be - y, I think.) | | I definitely *wasn't* talking about the atomicity of the two operations | - just the ordering. | | -- | Jon Skeet - <skeet@pobox.com> | http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet | If replying to the group, please do not mail me too |
|
#20
| |||
| |||
| William Stacey [C# MVP] wrote: > So are you saying the JIT can reorder these two lines: > int a = x; > int b = y; > > Like so: > int b = y; > int a = x; Yes, if x and y are not volatile locations. The language of the spec is that reads and writes to volatile locations are the only observable side effects of memory access; memory accesses may be arbitrarily reordered if they aren't volatile. For example, if the value of y has been loaded to a register because it was used somewhere before the line 'int a = x;', then the value of y used in the line 'int b = y;' may predate the actual in-memory value of x, because the value may be used from the register, rather than freshly loading it from memory. So, volatile can inhibit these kinds of optimizations (avoiding redundant loads). There's more to it than that, volatile reads have acquire semantics, volatile writes release semantics. That has stronger guarantees than just inhibiting optimization, as it affects e.g. write buffer reordering in some processors. -- Barry -- http://barrkel.blogspot.com/ |
![]() |
| Thread Tools | |
| Display Modes | |
In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.