Kay
Kay

Reputation: 797

C volatile memory model

Does the volatile keyword enforce visibility across threads? For example:

volatile int bar;
mutex mut;

void foo()
{
    bar = 4;

    // (*) Possible other thread changes to `bar`. No instructions here,
    // just time that passes.

    lock(&mut);

    // (1) If 'bar' had _not_ been declared 'volatile', would the compiler
    // be allowed to assume 'bar' is '4' here?
    //
    // (2) If 'bar' _is_ declared 'volatile', the compiler is 
    // forced to add the necessary instructions such that changes to
    // 'bar' that may have occurred during (*) are visible here.

    unlock(&mut)
}

Not asking about atomicity or ordering (I'm assuming any sane implementation of lock(mutex) adds the appropriate memory and compiler fences, where appropriate for the architecture) - simply a question of visibility.

Upvotes: 2

Views: 177

Answers (2)

P.P
P.P

Reputation: 121357

(1) If 'bar' had not been declared 'volatile', would the compiler be allowed to assume 'bar' is '4' here?

The property of volatile is really simple to understand: read it from memory location every time without optimising anything in relation that. Whether or not, there are multiple threads, a volatile qualified variable still holds the same property.

Does it mean volatile enforces "visibility" across threads?

It may do so as a side effect of its property. But that shouldn't be necessary in a multi-threaded program. Using a proper synchronisation primitive (e.g. a mutex or an atomic variable), a compiler must enforce the visibility or the last stored value in an object across different threads. This is case in both C11 and POSIX threads. A compiler that supports multi-threading programs should be able to generate code correct code that enforces this without requiring volatile. So, the answer is no; you don't need volatile in multi-threaded programs to enforce changes to objects (variables).

Upvotes: 1

Jean-François Fabre
Jean-François Fabre

Reputation: 140148

Even if you don't tag bar as volatile, the compiler cannot be sure that the value hasn't been modified in the meanwhile since it is a global value.

So it has to read it again (mutex functions are called, it could be any function getting access to bar and change it), volatile or not.

It would be different for a local value, binding, say, on a hardware register that may change independently of the program execution, where the volatile keyword would be required.

Upvotes: 1

Related Questions