5

I'm aware of the use of volatile in Java. That is (based on the wikipedia article):

There is a global ordering on the reads and writes to a volatile variable. This implies that every thread accessing a volatile field will read its current value before continuing, instead of (potentially) using a cached value.

I also I'm aware that there exists the volatile keyword in C but in a quite different context, mainly to be used in memory-mapped I/O.

So I was wondering, is there some construct like Java's volatile in C? Which will prevent reading cached values of a variable?

If it doesn't exist in C, is there perhaps a library with such a construct, like pthread?

Fooko R.
  • 129
  • 1
  • 10
  • You want memory barriers to order reads/writes, but they're platform specific, not part of C – Flexo Feb 10 '12 at 18:01
  • @awoodland I don't want all my threads to wait each other in a specific point before the continue. From what I get, this is what memory barriers do. I just want when reading a variable, to be sure the latest value of this variable is being read and not a cached one. – Fooko R. Feb 10 '12 at 18:12
  • 1
    @Fooko You're thinking of something different there. Memory barriers are low level instructions to the CPU basically. Java's `volatile` is implemented with memory barriers – Voo Feb 10 '12 at 18:18
  • 1
    http://www.kernel.org/doc/Documentation/memory-barriers.txt has a good discussion on barriers – Flexo Feb 10 '12 at 18:19
  • @awoodland Nice link that. Good, understandable summary there. – Voo Feb 10 '12 at 18:23

2 Answers2

5

volatile in C is basically an anachronism that was intended for a completely different scenario and is NOT useful for multi threaded programming. For some reasons or another even the newest c++ standard couldn't give it more meaning but had to invent a new keyword instead.

Mind you this means volatile as defined by the C standard is useless, compilers may give you additional guarantees (I know that MS VC does and I think it gives basically the same guarantees as does volatile in java) but that means the program is locked to that one compiler. Most compilers also have some intrinsics to insert memory barriers, which is a bit more explicit but again not portable per se.

In practice you're probably best of using some higher level threading library that offers the right tools for the job. E.g. POSIX gives you low level memory barriers afaik.

On the c++ site it's better since 0x11 - the standard does offer std::atomic_thread_fence and atomic variables. Note though that the c++0x11 memory model is NOT identical to the java one, so you'll have to be careful when porting.

Voo
  • 29,040
  • 11
  • 82
  • 156
  • Thank you for answering. From what I get, barriers/fences is a different concept as I already said to awoodland. I think that barriers are used to make all threads wait in a specific point all other threads before continuing their work. I don't want my threads to wait for the others, I just want to make that everything they read is consistent on what exists in memory at that time and not some cached values. Of course I would like also to NOT have reoreding, but I still don't get how barrier can help in this? – Fooko R. Feb 10 '12 at 18:17
  • @Fooko See awoodlands and my answer to your point there. You're thinking of Java's CyclicBarrier it seems. The one is a extremely low level concept the other is a pretty high level construct that most threading libraries offer. The [wiki article](http://en.wikipedia.org/wiki/Memory_barrier) explains the basics shortly, but awoodlands link seems really good on first glance. – Voo Feb 10 '12 at 18:20
  • @Fooko R.: A memory fence/barrier is NOT a thread barrier. A memory fence is a special instruction that does not allow the reordering of loads or stores or both with respect to the fence itself. So practically a load that is before the fence cannot be reordered with a load that is after the fence. – Tudor Feb 10 '12 at 18:20
  • Ok, I will have a read of both the wiki article and the awoodlands link. Thanks! @Tudor but so it seems I should be using a fence after each read or write in my program. E.g. `read / fence / write / fence / read / fence / read / fence / ... ` isn't there an easier way to let the compiler(+ hardware) now that I don't want any reordering to be used? – Fooko R. Feb 10 '12 at 18:28
  • AFAIK the C11 memory model is essentially the same as the C++11 memory model. – han Feb 10 '12 at 18:43
  • @Tudor After reading the wiki article, I guess after each read/load I should write `asm("mfence");`. Isn't that quite masochistic? – Fooko R. Feb 10 '12 at 18:48
  • @Fooko Well you have to know yourself when you need the memory barriers and when not. Usually it's a much better idea to leave this low level stuff to people who know what they're doing :) Also depending on the compiler including `asm` instructions disables all/most optimizations (gcc has a complex asm system that avoids this, MSVC does not) so that's not a great solution in its own. – Voo Feb 10 '12 at 19:17
  • Thank you Voo for your answer :) Really helped a lot. – Fooko R. Feb 10 '12 at 20:25
3

The behavior of volatile isn't necessarily different; it's the platform and context that is different. You specifically mentioned memory-mapped devices in your question. If you have a memory mapped device like some piece of hardware that can flip a register that is represented by a variable in your code, then obviously you want a way to indicate that. If you don't, then the compiler will always work under the assumption that the only system that can change your code is your program and might optimize it out.

A good example would be if you are using a variable in a decision or control flow situation. If this variable is never manipulated in your code directly but could be flipped by a signal or some memory-mapped hardware, the compiler might optimize the decision condition in to a boolean value since it will assume the value won't change. So when the hardware flips the value, it doesn't reflect in the running code because of the compiler optimizations.

Java "caches" are basically the same behavior. Your disconnect seems to be coming from the fact that you aren't making the mental bridge between C being compiled code and Java being JIT compiled byte code running inside of a virtual machine. Java inherits its volatile behavior from C but the consequences of this behavior are drastically different because of the runtime context.

Doug Stephen
  • 7,181
  • 1
  • 38
  • 46