Re: When is "volatile& quot; used instead of "lock" ; ?
"Ben Voigt" <rbv@nospam.nos pamwrote in message
news:%23MmyV$gn HHA.4196@TK2MSF TNGP06.phx.gbl. ..
Sure, but this was not my point, the point is that Interlocked operations
imply barriers, all or not full. "volatile" implies full barriers, so they
both imply barriers, but they serve different purposes. One does not exclude
the other, but that doesn't mean they should always be used in tandem, all
depends on what you want to achieve in your code, what guarantees you want.
Anyway, the docs do not impose it, the C# docs on Interlocked don't even
mention volatile, and the Win32 docs (Interlocked API's) don't spend a word
on the volatile argument. (note that the volatile was added to the
signature after NT4 SP1).
Sorry but you are mixing native code and managed code semantics. What I
mean, is that the semantics of the C (native) volatile is not the same as
the semantics of C# 'volatile'. So when I refered to C++ supporting
"volatile" I was refering to managed dialects (VC7.x and VC8) who's volatile
semantics are obviously the same as all other languages
I don't wanna discuss the semantics of volatile in standard C/c++ here, they
are so imprecise that IMO it will lead to an endless dicussion, not relevant
to C#.
Also I don't wanna discuss the semantics of Win32 Interlocked either, "Win32
interlocked API's" do accept pointers to volatile items, while .NET does
accept "volatile pointers" (in unsafe context) as arguments of a method
call, but treats the item as non volatile. Also, C#, will issue a warning
when passing a volatile field (passed by ref is required by Interlocked
operations), that means that the item will be treated as volatile, but the
reference itself will not.
Where in the docs (MSDN Platform SDK etc..) do they state that Interlocked
should always be on volatile items?
>
You are claiming that you should almost never use lock free techniques,
and thus volatile should be rare. This hardly contradicts my statement
that volatile should always be used in lock free programming.
Kind of, I'm claiming that you should rarely use lock-free techniques when
using C# in mainstream applications, I've seen too many people trying to
implement lock free code, and if you ask "why", the answer is mostly
"performanc e", and if you asked if the measured their "locked "
implementation, the answer is mostly, well I have no 'locked'
implementation, this is what I call "premature optimization" without any
guarantees, other than probably producing unrealiable code, which is (IMO)
more important than performant code .
IMO the use of volatile should be rare in the sense that you better use
locks and only use volatile for the most simple cases (which doesn't imply
'rare'), for instance when you need to guarantee that all possible observers
of a field (of type accepted by volatile) see the same value when that value
has been written to by another observer.
Remember "volatile" is something taken care of by the JIT, all it does is
eliminate some of the possible optimizations like (but not restricted to):
- volatile items cannot be registered...
- multiple stores cannot be suppressed...
- re-ordering is restricted.
- ...
But keep in mind that, 'volatile' suppresses optimizations for all possible
accesses, even when not subject to multiple observers (threads), and that
volatile fields accesses can move, some people think they can't....
Willy.
"Ben Voigt" <rbv@nospam.nos pamwrote in message
news:%23MmyV$gn HHA.4196@TK2MSF TNGP06.phx.gbl. ..
>
"Willy Denoyette [MVP]" <willy.denoyett e@telenet.bewro te in message
news:BFF370C9-379B-4B12-A00F-CF8195C64E1E@mi crosoft.com...
>
Let's look at the Win32 declaration for an Interlocked function:
>
LONG InterlockedExch ange(
LONG volatile* Target,
LONG Value
);Clearly, Target is intended to be the address of a volatile variable.
Sure, you can pass a non-volatile pointer, and there is an implicit
conversion, but if you do *the variable will be treated as volatile only
inside InterlockedExch ange*. The compiler can still do anything outside
InterlockedExch ange, because it is dealing with a non-volatile variable.
"Willy Denoyette [MVP]" <willy.denoyett e@telenet.bewro te in message
news:BFF370C9-379B-4B12-A00F-CF8195C64E1E@mi crosoft.com...
>"Ben Voigt" <rbv@nospam.nos pamwrote in message
>news:uXg8juTnH HA.2296@TK2MSFT NGP03.phx.gbl.. .
>>
>>
>>
>No, not at all. Interlocked operations imply a full fence, that is, reads
>have acquire and writes have release semantics. That means that the JIT
>may not register these variables nor store them locally and cannot move
>stuff around them.
>news:uXg8juTnH HA.2296@TK2MSFT NGP03.phx.gbl.. .
>>>
>>"Willy Denoyette [MVP]" <willy.denoyett e@telenet.bewro te in message
>>news:1B1A6E 75-67F7-4B6E-B858-C7517C5BEA43@mi crosoft.com...
>>>"Ben Voigt" <rbv@nospam.nos pamwrote in message
>>>news:uln5JOM nHHA.3968@TK2MS FTNGP06.phx.gbl ...
>>>>>
>>>><ben.biddin gton@gmail.comw rote in message
>>>>news:117976 1300.206885.512 30@z28g2000prd. googlegroups.co m...
>>>>>On May 21, 3:35 pm, Samuel R. Neff <samueln...@nom ail.comwrote:
>>>>>>When is it appropriate to use "volatile" keyword? The docs simply
>>>>>>state:
>>>>>>>
>>>>>>"
>>>>>>The volatile modifier is usually used for a field that is accessed
>>>>>>by
>>>>>>multipl e threads without using the lock Statement (C# Reference)
>>>>>>stateme nt to serialize access.
>>>>>>"
>>>>>>>
>>>>>>But when is it better to use "volatile" instead of "lock" ?
>>>>>>>
>>>>>>Thanks,
>>>>>>>
>>>>>>Sam
>>>>>>>
>>>>>>------------------------------------------------------------
>>>>>>We're hiring! B-Line Medical is seeking .NET
>>>>>>Developer s for exciting positions in medical product
>>>>>>developme nt in MD/DC. Work with a variety of technologies
>>>>>>in a relaxed team environment. See ads on Dice.com.
>>>>>>
>>>>>You can also the System.Threadin g.Interlocked class which maintains
>>>>>volatile semantics.
>>>>>
>>>>You should use volatile and Interlocked together, neither fully
>>>>replaces the other.
>>>>>
>>>>
>>>Not necessarily, there is no need for volatile, as long you Interlock
>>>consistent ly across all threads in the process. This means that once
>>>you access a shared variable using Interlock, all threads should use
>>>Interlock.
>>>
>>I don't think so, actually. Without volatile semantics, the compiler is
>>free to cache the value of any parameter, including in/out parameters.
>>Say you are calling an Interlocked method in a loop. If the variable is
>>not volatile, the compiler can actually call Interlocked on a local
>>copy, and then write the value to the real variable once, at the end of
>>the loop (and worse, it can do so in a non-atomic way). Anything that
>>maintains correct operation from the perspective of the calling thread
>>is permissible for non-volatile variable access. Why would a compiler
>>do this? For optimal use of cache. By using a local copy of a variable
>>passed byref, locality of reference is improved, and additionally, a
>>thread's stack (almost) never incurs cache coherency costs.
>>>
>>Note that this is not a problem for pass-by-pointer, which must use the
>>true address of the referenced variable in order to enable pointer
>>arithmetic. But pointer arithmetic isn't allowed for tracking handles, a
>>handle is an opaque value anyway.
>>>
>>For lockless data structures, always use volatile. And then stick that
>>volatile variable close in memory to what it is protecting, because CPU
>>cache has to load and flush an entire cache line at once, and volatile
>>write semantics require flushing all pending writes.
>>>
>>>>
>>>Willy.
>>>>
>>>
>>>
>>"Willy Denoyette [MVP]" <willy.denoyett e@telenet.bewro te in message
>>news:1B1A6E 75-67F7-4B6E-B858-C7517C5BEA43@mi crosoft.com...
>>>"Ben Voigt" <rbv@nospam.nos pamwrote in message
>>>news:uln5JOM nHHA.3968@TK2MS FTNGP06.phx.gbl ...
>>>>>
>>>><ben.biddin gton@gmail.comw rote in message
>>>>news:117976 1300.206885.512 30@z28g2000prd. googlegroups.co m...
>>>>>On May 21, 3:35 pm, Samuel R. Neff <samueln...@nom ail.comwrote:
>>>>>>When is it appropriate to use "volatile" keyword? The docs simply
>>>>>>state:
>>>>>>>
>>>>>>"
>>>>>>The volatile modifier is usually used for a field that is accessed
>>>>>>by
>>>>>>multipl e threads without using the lock Statement (C# Reference)
>>>>>>stateme nt to serialize access.
>>>>>>"
>>>>>>>
>>>>>>But when is it better to use "volatile" instead of "lock" ?
>>>>>>>
>>>>>>Thanks,
>>>>>>>
>>>>>>Sam
>>>>>>>
>>>>>>------------------------------------------------------------
>>>>>>We're hiring! B-Line Medical is seeking .NET
>>>>>>Developer s for exciting positions in medical product
>>>>>>developme nt in MD/DC. Work with a variety of technologies
>>>>>>in a relaxed team environment. See ads on Dice.com.
>>>>>>
>>>>>You can also the System.Threadin g.Interlocked class which maintains
>>>>>volatile semantics.
>>>>>
>>>>You should use volatile and Interlocked together, neither fully
>>>>replaces the other.
>>>>>
>>>>
>>>Not necessarily, there is no need for volatile, as long you Interlock
>>>consistent ly across all threads in the process. This means that once
>>>you access a shared variable using Interlock, all threads should use
>>>Interlock.
>>>
>>I don't think so, actually. Without volatile semantics, the compiler is
>>free to cache the value of any parameter, including in/out parameters.
>>Say you are calling an Interlocked method in a loop. If the variable is
>>not volatile, the compiler can actually call Interlocked on a local
>>copy, and then write the value to the real variable once, at the end of
>>the loop (and worse, it can do so in a non-atomic way). Anything that
>>maintains correct operation from the perspective of the calling thread
>>is permissible for non-volatile variable access. Why would a compiler
>>do this? For optimal use of cache. By using a local copy of a variable
>>passed byref, locality of reference is improved, and additionally, a
>>thread's stack (almost) never incurs cache coherency costs.
>>>
>>Note that this is not a problem for pass-by-pointer, which must use the
>>true address of the referenced variable in order to enable pointer
>>arithmetic. But pointer arithmetic isn't allowed for tracking handles, a
>>handle is an opaque value anyway.
>>>
>>For lockless data structures, always use volatile. And then stick that
>>volatile variable close in memory to what it is protecting, because CPU
>>cache has to load and flush an entire cache line at once, and volatile
>>write semantics require flushing all pending writes.
>>>
>>>>
>>>Willy.
>>>>
>>>
>>>
>>
>>
>No, not at all. Interlocked operations imply a full fence, that is, reads
>have acquire and writes have release semantics. That means that the JIT
>may not register these variables nor store them locally and cannot move
>stuff around them.
Let's look at the Win32 declaration for an Interlocked function:
>
LONG InterlockedExch ange(
LONG volatile* Target,
LONG Value
);Clearly, Target is intended to be the address of a volatile variable.
Sure, you can pass a non-volatile pointer, and there is an implicit
conversion, but if you do *the variable will be treated as volatile only
inside InterlockedExch ange*. The compiler can still do anything outside
InterlockedExch ange, because it is dealing with a non-volatile variable.
imply barriers, all or not full. "volatile" implies full barriers, so they
both imply barriers, but they serve different purposes. One does not exclude
the other, but that doesn't mean they should always be used in tandem, all
depends on what you want to achieve in your code, what guarantees you want.
Anyway, the docs do not impose it, the C# docs on Interlocked don't even
mention volatile, and the Win32 docs (Interlocked API's) don't spend a word
on the volatile argument. (note that the volatile was added to the
signature after NT4 SP1).
And, it can't possibly change behavior when InterlockedExch ange is called,
because the call could be made from a different library, potentially not
yet loaded.
>
because the call could be made from a different library, potentially not
yet loaded.
>
mean, is that the semantics of the C (native) volatile is not the same as
the semantics of C# 'volatile'. So when I refered to C++ supporting
"volatile" I was refering to managed dialects (VC7.x and VC8) who's volatile
semantics are obviously the same as all other languages
I don't wanna discuss the semantics of volatile in standard C/c++ here, they
are so imprecise that IMO it will lead to an endless dicussion, not relevant
to C#.
Also I don't wanna discuss the semantics of Win32 Interlocked either, "Win32
interlocked API's" do accept pointers to volatile items, while .NET does
accept "volatile pointers" (in unsafe context) as arguments of a method
call, but treats the item as non volatile. Also, C#, will issue a warning
when passing a volatile field (passed by ref is required by Interlocked
operations), that means that the item will be treated as volatile, but the
reference itself will not.
Consider this:
>
/* compilation unit one */
void DoIt(LONG *target)
{
LONG value = /* some long calculation here */;
if (value != InterlockedExch ange(target, value))
{
/* some complex operation here */
}
}
>
/* compilation unit two */
>
extern void DoIt(LONG * target);
extern LONG shared;
>
void outer(void)
{
for( int i = 0; i < 1000; i++ )
{
DoIt(&shared);
}
}
>
Now, clearly, the compiler has no way of telling that DoIt uses
Interlocked access, since DoIt didn't declare volatile semantics on the
pointer passed in. So the compiler can, if desired, transform outer
thusly:
>
void outer(void)
{
LONG goodLocalityOfR eference = shared;
for( int i = 0; i < 1000; i++ )
{
DoIt(&goodLocal ityOfReference) ;
}
shared = goodLocalityOfR eference;
}
>
Except for one thing. In native code, pointers have values that can be
compared, subtracted, etc. So the compiler has to honestly pass the
address of shared. In managed code, with tracking handles, the compiler
doesn't have to preserve the address of the variable (that would, after
all, defeat compacting garbage collection). Oh, sure, the JIT has a lot
more information about what is being called than a native compiler does,
it almost gets rid of separate compilation units.... but not quite. With
dynamically loaded assemblies and reflection in the mix, it is just a
helpless as a "compile-time" compiler.
>
I'm fairly sure that the current .NET runtime doesn't actually do any such
optimization as I've described. But I wouldn't bet against such things
being added in the future, when NUMA architectures become so widespread
that the compiler has to optimize for them.
>
Be safe, use volatile on every variable you want to act volatile, which
includes every variable passed to Interlocked.
>
>
VC++, all versions, and all other PC compilers that I'm aware of (as in,
not embedded), support volatile to the extent needed to invoke an
interlocked operation. That is, the real variable is always accessed at
the time specified by the compiler. The memory fences are provided by the
implementation of Interlocked*, independent of the compiler version.
>
>
/* compilation unit one */
void DoIt(LONG *target)
{
LONG value = /* some long calculation here */;
if (value != InterlockedExch ange(target, value))
{
/* some complex operation here */
}
}
>
/* compilation unit two */
>
extern void DoIt(LONG * target);
extern LONG shared;
>
void outer(void)
{
for( int i = 0; i < 1000; i++ )
{
DoIt(&shared);
}
}
>
Now, clearly, the compiler has no way of telling that DoIt uses
Interlocked access, since DoIt didn't declare volatile semantics on the
pointer passed in. So the compiler can, if desired, transform outer
thusly:
>
void outer(void)
{
LONG goodLocalityOfR eference = shared;
for( int i = 0; i < 1000; i++ )
{
DoIt(&goodLocal ityOfReference) ;
}
shared = goodLocalityOfR eference;
}
>
Except for one thing. In native code, pointers have values that can be
compared, subtracted, etc. So the compiler has to honestly pass the
address of shared. In managed code, with tracking handles, the compiler
doesn't have to preserve the address of the variable (that would, after
all, defeat compacting garbage collection). Oh, sure, the JIT has a lot
more information about what is being called than a native compiler does,
it almost gets rid of separate compilation units.... but not quite. With
dynamically loaded assemblies and reflection in the mix, it is just a
helpless as a "compile-time" compiler.
>
I'm fairly sure that the current .NET runtime doesn't actually do any such
optimization as I've described. But I wouldn't bet against such things
being added in the future, when NUMA architectures become so widespread
that the compiler has to optimize for them.
>
Be safe, use volatile on every variable you want to act volatile, which
includes every variable passed to Interlocked.
>
>Think of this, what would be the use of Interlocked operation when used
>in languages that don't support volatile (like VB.NET) or good old C/C++
>(except VC7 and up).
>in languages that don't support volatile (like VB.NET) or good old C/C++
>(except VC7 and up).
VC++, all versions, and all other PC compilers that I'm aware of (as in,
not embedded), support volatile to the extent needed to invoke an
interlocked operation. That is, the real variable is always accessed at
the time specified by the compiler. The memory fences are provided by the
implementation of Interlocked*, independent of the compiler version.
>
should always be on volatile items?
>I also don't agree with your statement that you should *always* use
>volatile in lock free or low lock scenario's. IMO, you should almost
>never use volatile, unless you perfectly understand the semantics of the
>memory model of the CLR/CLI (ECMA differs from V1.X differs from V2 for
>instance) and the memory model of the CPU (IA32 vs. IA64). The last year
>I was involved in the resolution of a number of nasty bugs , all of them
>where the result of people trying to out-smart the system by applying
>lock free or low lock techniques using volatile, since then whenever I
>see volatile I'm getting very suspicious, really.......
>volatile in lock free or low lock scenario's. IMO, you should almost
>never use volatile, unless you perfectly understand the semantics of the
>memory model of the CLR/CLI (ECMA differs from V1.X differs from V2 for
>instance) and the memory model of the CPU (IA32 vs. IA64). The last year
>I was involved in the resolution of a number of nasty bugs , all of them
>where the result of people trying to out-smart the system by applying
>lock free or low lock techniques using volatile, since then whenever I
>see volatile I'm getting very suspicious, really.......
You are claiming that you should almost never use lock free techniques,
and thus volatile should be rare. This hardly contradicts my statement
that volatile should always be used in lock free programming.
using C# in mainstream applications, I've seen too many people trying to
implement lock free code, and if you ask "why", the answer is mostly
"performanc e", and if you asked if the measured their "locked "
implementation, the answer is mostly, well I have no 'locked'
implementation, this is what I call "premature optimization" without any
guarantees, other than probably producing unrealiable code, which is (IMO)
more important than performant code .
IMO the use of volatile should be rare in the sense that you better use
locks and only use volatile for the most simple cases (which doesn't imply
'rare'), for instance when you need to guarantee that all possible observers
of a field (of type accepted by volatile) see the same value when that value
has been written to by another observer.
Remember "volatile" is something taken care of by the JIT, all it does is
eliminate some of the possible optimizations like (but not restricted to):
- volatile items cannot be registered...
- multiple stores cannot be suppressed...
- re-ordering is restricted.
- ...
But keep in mind that, 'volatile' suppresses optimizations for all possible
accesses, even when not subject to multiple observers (threads), and that
volatile fields accesses can move, some people think they can't....
Willy.
Comment