Search code examples
ccompiler-constructionconcurrencyvolatile

Restrictions on non volatile variables in C


I Would like to understand what Restrictions if any does the compiler have with regards to non volatile variables in C.

I'm not sure if its true or not, but I've been told that if you have the following code:

int x;
...
void update_x() {
  lock();
  x = x*5+3;
  unlock();
} 

You must acquire the lock to read x because even tough the compiler is unlikely to do it is technically legal for it to store intermediate calculation such as x*5 into x, and so the read might read an intermediate value. so my first question is whether it is indeed the case? if not, why not?

If it is, I have a followup question, is there anything that's prevents to compiler from using x as a temporary storage before or after taking the lock? (Assuming the compiler can prove that a single thread executing the program will not notice it).

If not, does that mean that any program that has non volatile shared variables is technically undefined even if all the accesses are protected by locks?

Thanks, Ilya


Solution

  • Prior to C11, the answer is No, as the spec doesn't define anything about what multiple threads do, so any program that uses multiple threads where one thread writes an object and another thread reads it is undefined behavior.

    With C11, there's actually a memory model that talks about multiple threads and data races, so the answer is Yes, as long as the lock/unlock routines do certain synchronization operations (involving either library functions that do the synchronization or operations on special _Atomic objects).

    Since the C11 spec is attempting to codify behavior of existing implementations (for the most part), it is likely that any code that does what it requires (ie, using a implementation provided library for locking, or implementation provided extensions for atomic operations) will work correctly even on pre-C11 implementations.

    Section 5.2.1.4 of the C11 spec covers this.