Question

Is there any guarantee by any commonly followed standard (ISO C or C++, or any of the POSIX/SUS specifications) that a variable (perhaps marked volatile), not guarded by a mutex, that is being accessed by multiple threads will become eventually consistent if it is assigned to?

To provide a specific example, consider two threads sharing a variable v, with initial value zero.

Thread 1: v = 1

Thread 2: while(v == 0) yield();

Is thread 2 guaranteed to terminate eventually? Or can it conceivably spin forever because the cache coherency never kicks in and makes the assignment visible in thread 2's cache?

I'm aware the C and C++ standards (before C++0x) do not speak at all about threads or concurrency. But I'm curious if the C++0x memory model, or pthreads, or anything else, guarantees this. (Apparently this does actually work on Windows on 32-bit x86; I'm wondering if it's something that can be relied on generally or if it just happens to work there).

Was it helpful?

Solution

It's going to depend on your architecture. While it is unusual to require an explicit cache flush or memory sync to ensure memory writes are visible to other threads, nothing precludes it, and I've certainly encountered platforms (including the PowerPC-based device I am currently developing for) where explicit instructions have to be executed to ensure state is flushed.

Note that thread synchronisation primitives like mutexes will perform the necessary work as required, but you don't typically actually need a thread synchronisation primitive if all you want is to ensure the state is visible without caring about consistency - just the sync / flush instruction will suffice.

EDIT: To anyone still in confustion about the volatile keyword - volatile guarantees the compiler will not generate code that explicitly caches data in registers, but this is NOT the same thing as dealing with hardware that transparently caches / reorders reads and writes. Read e.g. this or this, or this Dr Dobbs article, or the answer to this SO question, or just pick your favourite compiler that targets a weakly consistent memory architecture like Cell, write some test code and compare what the compiler generates to what you'd need in order to ensure writes are visible to other processes.

OTHER TIPS

If I've understood correctly the relevant sections, C++0X won't guaranteed it for standalone variable or even volatile one (volatile isn't designed for that use), but will introduce atomic types for which you'll have the guarantee (see header <atomic>).

First off, if it's not marked volatile there is a good chance the compiler may only load it once. So regardless of whether the memory eventually changes, there is no guarantee the compile will set it.

Since you explicitly say "no mutexes", pthreads doesn't apply.

Beyond that, since C++ does not have a memory model, it depends on the hardware architecture.

This is a potential data race.

With respect to POSIX thread, this is UB. Same with C++ I believe.

In practice I cannot imagine how it could fail.

Is thread 2 guaranteed to terminate eventually? Or can it conceivably spin forever because the cache coherency never kicks in and makes the assignment visible in thread 2's cache?

If the variable is not volatile, you have no guarantees. Pre-C++0x, the standard just has nothing to say about threads, and since the variable is not volatile, reads/writes are not considered observable side effects, so the compiler is allowed to cheat. Post-C++0x, it's a race condition, which is explicitly stated to be undefined behavior.

If the variable is volatile, you get the guarantee that reads/writes will happen, and that the compiler won't be reordered with respect to other volatile memory accesses. (However, this does not by itself guarantee that the CPU won't reorder these memory accesses -- just that the compiler won't)

But you have no guarantee that it won't be reordered with respect to other non-volatile accesses, so you might not get the behavior you expected. In particular, some of the instructions after the while loop, which you're trying to "protect" may be moved up ahead of the loop if the compiler deems it safe (and beneficial) to do so. But in performing this analysis, it only looks at the current thread, not what happens in other threads.

So no, in general, it is not guaranteed to work correctly, even with volatile. It might, and it probably often will, but not always (and it depends on what happens after the loop). It depends on how far the compiler is willing to go with optimizations. But it is allowed to go far enough to break the code. So don't rely on it. If you want to synchronize around something like this, use memory barriers. That's what they're for. (And if you do that, you don't even need the volatile any more)

I think it will work eventually on any platform, but no idea on the delay that you may see.

But honestly, it is really bad style to do a polling wait for an event. Even though you do a yield your process will be rescheduled again and again, without doing anything.

Since you already know how to place a variable somewhere where it is accessible to both, why not use the right tools to do a wait that doesn't eat up resources? A pair of pthread_mutex_t and pthread_cond_t should perfectly do the trick.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top