views:

76

answers:

2

Background

I've been reading through various books and articles to learn about processor caches, cache consistency, and memory barriers in the context of concurrent execution. So far though, I have been unable to determine whether a common coding practice of mine is safe in the strictest sense.

Assumptions

  1. The following pseudo-code is executed on a two-processor machine:

    int sharedVar = 0;
    
    
    myThread()
    {
        print(sharedVar);
    }
    
    
    main()
    {
        sharedVar = 1;
        spawnThread(myThread);
        sleep(-1);
    }
    
  2. main() executes on processor 1 (P1), while myThread() executes on P2.

  3. Initially, sharedVar exists in the caches of both P1 and P2 with the initial value of 0 (due to some "warm-up code" that isn't shown above.)

Question

Strictly speaking – preferably without assuming any particular type of CPU – is myThread() guaranteed to print 1?

With my newfound knowledge of processor caches, it seems entirely possible that at the time of the print() statement, P2 may not have received the invalidation request for sharedVar caused by P1's assignment in main(). Therefore, it seems possible that myThread() could print 0.

References

These are the related articles and books I've been reading:

  1. Shared Memory Consistency Models: A Tutorial
  2. Memory Barriers: a Hardware View for Software Hackers
  3. Linux Kernel Memory Barriers
  4. Computer Architecture: A Quantitative Approach
A: 

I'll speak only to Java here: myThread() is guaranteed to print 1, due to the happens before definition from the The Java Language Specification (Section 17.4.5).

The write to sharedVar in main() happens before spawning the thread with function myThread() because the variable assignment comes first in program order. Next, spawning a thread happens before any actions in the thread being started. By the transitivity of the definition in Section 17.4.5 (hb(x, y) and hb(y, z) implies hb(x, z)), writing to the variable sharedVar happens before print() reads sharedVar in myThread().

You might also enjoy reading Brian Goetz's article Java theory and practice: Fixing the Java Memory Model, Part 2 covering this subject, as well as his book Java Concurrency in Practice.

seh
+1  A: 

Strictly speaking – preferably without assuming any particular type of CPU – is myThread() guaranteed to print 1?

Theoretically, it can print either 0 or 1, even on x86, since stores can move after loads on almost any architecture.

In practice, it would be hard to make myThread() print 0.
Spawning a thread will most likely function as an implicit store/release memory barrier, since it would probably:
- have at least one instruction along the execution path that results in a memory barrier - interlocked instructions, explicit memory barrier instructions, etc.,
- or the store would simply be retired/drained from the store buffer by the time myThread() is called, since setting up a new thread results in executing many instructions - among them, many stores.

andras