Re: multiple threads and volatile




Zeljko Vrba wrote:

On 2008-07-11, David Schwartz <davids@xxxxxxxxxxxxx> wrote:

The problem is that preventing caching in registers does not force
memory access. Modern CPUs have posted write buffers and may do
speculative fetches.

To put it in another way: volatile is necessary but not sufficient, because
if a variable is cached in a register, no memory barrier is going to make it
visible to another thread; see below.

Actually, it's not necessary. In fact, 'volatile' may disable
optimizations that are perfectly safe to use on multi-threaded code.

Nonsense. I've made many custom synchronizations functions and that do
not have a single 'volatile' among them. In fact, 'volatile' wouldn't
help in any way, since it doesn't have precisely-defined multi-
processor semantics.

OK, synchronization was a bad word. For example:

static unsigned x;

void thread1(void)
{
unsigned local = x;

while(local+10 > x)
++y;
}

void thread2(void)
{
while(1)
atomic_inc_uint(&x); // also arranges global visibility
}

Let's say that the above is a complete compilation unit, the variable x is
static and the compiler can prove that its address is not exported to other
code via some pointer, and that thread1 does not modify x on its own. Why is
the compiler, even without volatile, not allowed to cache x in a register in
thread1?

That is one of a possible universe of problems with this code. That
'volatile' fixes this one specific potential problem does not make it
necessary or sufficient. It's not sufficient because of the universe
of other problems (the CPU may consolidate the reads if it's smart
enough). It's not necessary because every threading library in
existence provides correct solutions to this problem.

You might ask why the compiler doesn't see the 'volatile' keyword and
workaround all these other possible problems. It could put memory
barriers before and after 'volatile' accesses, for example. It could
workaround prefetches and write posting buffers. Some have argued that
compilers that don't do this are broken and that's not their problem
-- it is still right to use 'volatile' here.

But they are wrong. The 'volatile' keyword *does* have defined
semantics in the C standard. It does very specific things with signals
and longjmp, for example. Making 'volatile' also work for code like
your example would penalize every single-threaded program that uses
'volatile' *properly* for no good reason.

That is why there is *no* mainstream threading standard in existence
that specifies that 'volatile' is sufficient. And because other
sufficient means are provided, it is not necessary either.

DS
.



Relevant Pages