In other words, can I do something with a volatile variable that could not also be solved with a normal variable an开发者_如何学Cd the Interlocked class?
EDIT: question largely rewritten
To answer this question, I dived a bit further in the matter and found out a few things about volatile
and Interlocked
that I wasn't aware of. Let's clear that out, not only for me, but for this discussion and other people reading up on this:
volatile
read/write are supposed to be immune to reordering. This only means reading and writing, it does not mean any other action;- volatility is not forced on the CPU, i.e., hardware level (x86 uses acquire and release fences on any read/write). It does prevent compiler or CLR optimizations;
Interlocked
uses atomic assembly instructions for CompareExchange (cmpxchg
), Increment (inc
) etc;Interlocked
does use a lock sometimes: a hardware lock on multi processor systems; in uni-processor systems, there is no hardware lock;Interlocked
is different fromvolatile
in that it uses a full fence, where volatile uses a half fence.- A read following a write can be reordered when you use
volatile
. It can't happen withInterlocked
.VolatileRead
andVolatileWrite
have the same reordering issue as `volatile (link thanks to Brian Gideon).
Now that we have the rules, we can define an answer to your question:
- Technically: yes, there are things you can do with
volatile
that you cannot do withInterlocked
:- Syntax: you cannot write
a = b
wherea
orb
is volatile, but this is obvious; - You can read a different value after you write it to a volatile variable because of reordering. You cannot do this with
Interlocked
. In other words: you can be less safe withvolatile
then you can be withInterlocked
. - Performance:
volatile
is faster thenInterlocked
.
- Syntax: you cannot write
Semantically: no, because
Interlocked
simply provides a superset of operations and is safer to use because it applies full fencing. You can't do anything withvolatile
that you cannot do withInterlocked
and you can do a lot withInterlocked
that you cannot do with volatile:static volatile int x = 0; x++; // non-atomic static int y = 0; Interlocked.Increment(y); // atomic
Scope: yes, declaring a variable
volatile
makes it volatile for every single access. It is impossible to force this behavior any other way, hencevolatile
cannot be replaced withInterlocked
. This is needed in scenarios where other libraries, interfaces or hardware can access your variable and update it anytime, or need the most recent version.
If you'd ask me, this last bit is the actual real need for volatile
and may make it ideal where two processes share memory and need to read or write without locking. Declaring a variable as volatile
is much safer in this context then forcing all programmers to use Interlocked
(which you cannot force by the compiler).
EDIT: The following quote was part of my original answer, I'll leave it in ;-)
A quote from the the C# Programming Language standard:
For nonvolatile fields,optimization techniques that consider that reorder instructions can lead to unexpected and unpredictable results in multithreaded programs that access fields without synchronization such as that provided by the lock-statement. These optimizationscan be performed by the compiler, by the runtime system, or by hardware. For volatile fields, such reordering optimizations are restricted:
A read of a volatile field is called a volatile read. A volatile read has :acquire semantics"; that is, it is guaranteed to occur prior to any references to memory that occur after it in the instruction sequence.
A write of a volatile field is called a volatile write. A volatile write has "release semantics"; that is, it is guaranteed to happen after any memory references prior to the write instruction in the instruction sequence.
Update: question largely rewritten, corrected my original response and added a "real" answer
This is a fairly complex topic. I find Joseph Albahari's writeup to be one of the more definitive and accurate sources for multithreading concepts in the .NET Framework that might help answer your question.
But, to quickly summarizes there is a lot of overlap between the volatile
keyword and the Interlocked
class as far as how they can be used. And of course both go way above and beyond what you can do with a normal variable.
Yes - you can look at the value directly.
As long as you ONLY use the Interlocked class to access the variable then there is no difference. What volatile does is it tells the compiler that the variable is special and when optimizing it shouldn't assume that the value hasn't changed.
Takes this loop:
bool done = false;
...
while(!done)
{
... do stuff which the compiler can prove doesn't touch done...
}
If you set done
to true
in another thread you would expect the loop to exit. However - if done is not marked as volatile
then the compiler has the option to realize that the loop code can never change done
and it can optimize out the compare for exit.
This is one of the difficult things about multithread programming - many of the situations which are problems only come up in certain situations.
I won't attempt to be an authority on this subject but I would highly recommend that you take a look at this article by the vaunted Jon Skeet.
Also take a look at the final part of this answer which details what volatile
should be used for.
Yes, you can gain some performance by using a volatile variable instead of a lock.
Lock is a full memory barrier which can give you the same characteristics of a volatile variable as well as many others. As has already been said volatile just ensures that in multi-threaded scenarios if a CPU changes a value in its cache line, the other CPUs sees the value immediately but do not ensure any locking semantic at all.
The thing is lock is a lot more powerful than volatile and you should use volatile when you can to avoid unnecessary locks.
精彩评论