views:

263

answers:

5

As I read deeper and deeper into the meaning of the volatile keyword, I keep saying to myself "this is way into implementation, this should not be a part of a high level programming language".
I mean, the fact that CPUs cache the data should be interesting for the JIT compiler, not to the C# programmer.

A considerable alternative might be an attribute (say, VolatileAttribute).

What do you think?

+1  A: 

IIIRC, in C++ volatile was mainly about memory mapped I/O rather than cache. If you read the same port twice you get different answers. Still, I would agree with your assessment that this is more cleanly expressed in C# as an attribute.

On the other hand, most actual uses of volatile in C# can better be understood as thread lock anyway, so the choice of volatile is may be a little unfortunate.

Edit: Just to add: two links to show that in C/C++ `volatile is explicitly not for multithreading.

Muhammad Alkarouri
+3  A: 

Using an attribute would be acceptable, if it were the other way around, that is, the compiler would assume that all varaibles are volatile, unless explicitly marked with an attribute saying it was safe. That would be incredibly determental to performance.

Hence it's assumed that, since having a variable's value changed outside of the view of the compiler is an abberation, the compiler would assume that it is not happeing.

However, That could happen in a program so the language itself must have a way of showing that.

Also, you seems confused about "implementation details". The term refers to things the compiler does behind your back. This is not the case here. Your code is modifying a varaible outside of the view of the compiler. SInce it's in your code, it will always be true. Hence the langauge must be able to indicate that.

James Curran
+6  A: 

I think you got side-tracked. All the tech stuff about caching etc is part of an attempt to explain it in low level terms. The functional description for volatile would be "I might be shared". Given that by default nothing can be shared between threads, this is not altogether strange. And I think fundamental enough to warrant a keyword over an attribute, but I suppose it was largely influenced by historic decisions (C++)

One way to replace/optimize it is with VolatileRead() and VolatileWrite() calls. But that's even more 'implementation'.

Henk Holterman
+1  A: 

Well, I certainly agree, it is pretty horrible that such an implementation detail is exposed. It is however the exact same kind of detail that's exposed by the lock keyword. We are still very far removed from that bug generator to be completely removed from our code.

The hardware guys have a lot of work to do. The volatile keyword matters a lot of CPU cores with a weak memory model. The marketplace isn't been kind to them, the Alpha and the Itanium haven't done well. Not exactly sure why, but I suspect that the difficulty of writing solid threaded code for these cores has a lot to do with it. Getting it wrong is quite a nightmare to debug. The verbiage in the MSDN Library documentation for volatile applies to these kind of processors, it otherwise is quite inappropriate for x86/x64 cores and makes it sound that the keyword is doing far more than it really does. Volatile merely prevents variable values from being stored in CPU registers on those cores.

Unfortunately, volatile still matters on x86 cores in very select circumstances. I haven't yet found any evidence that it matters on x64 cores. As far as I can tell, and backed up by the source code in SSCLI20, the Opcodes.Volatile instruction is a no-op for the x64 jitter, changing neither the compiler state nor emitting any machine code. That's heading the right way.

Generic advice is that wherever you're contemplating volatile, using lock or one of the synchronization classes should be your first consideration. Avoiding them to try to optimize your code is a micro-optimization, defeated by the amount of sleep you'll lose when your program is exhibiting thread race problems.

Hans Passant
The Thread.VolatileRead and Thread.VolatileWrite methods iclude calls to Thread.MemoryBarrier. If the volatile keyword is a no-op, this would mean that the volatile keyword works differently than the VolatileRead and VolatileWrite methods. Yikes! (And no, Thread.MemoryBarrier had better not be a no-op. x86 and x64 CPUs have store buffers which can result in reordering of store followed by load. Store followed by load is central to Dekker's, so Dekker's breaks on these archs if memory barriers are not used. Good resource is http://www.cl.cam.ac.uk/~pes20/weakmemory/cacm.pdf.)
binarycoder
They don't include a barrier, Titanium was far more fickle than that. Flushing pending reads and writes was separate. There was acquire crap too. I think, I've never been knowingly within a 500 mile radius of one. Doesn't feel like a loss.
Hans Passant
A: 

volatile in c# emits the correct barriers, or fences, which would matter to the programmer doing multi-thread work. Bear in mind, that the compiler, runtime, and the processor all can reorder reads/writes to some degree (each has its own rules). Though CLR 2.0 has a stronger memory model that what CLI ECMA specifies, the CLR memory model still is not the strictest memory model so you have a need for volatile in C#.

As an attribute, I don't think you can use attributes inside a method body, so the keyword is necessary.

Chris O