O_o
I think you somehow misunderstood your own assertion.
Code:
result = f();
result_of_g = g();
result_of_h = h();
result += result_of_g * result_of_h;
If the compiler changes the order these functions are called within a thread atomic operations and locks do not reorder them in any way.
If the compiler reorders sequence points for whatever reason you can't reason about the ultimate operation even without threads.
When threads enter into the equation different threads may see the results of different shared operations at different times; atomic operations and locking can order the visibility of such results across threads.
The point grumpy is making has nothing to do with threads and so threading primitives do not change anything.
If we elaborate on the above example by pretending these facilities are actually locking primitives we can see more about what is going on with sequence points.
Code:
resultLock = fGetLock();
result_of_gSharedData = gSharedUtility();
result_of_hUnlockError = hUnlock(resultLock);
If the compiler reorders these sequence points you can't reason about the code at all. You don't know if the result is thread safe. You don't know anything about the sequence of operations.
Code:
result_of_hUnlockError = hUnlock(resultLock);
resultLock = fGetLock();
result_of_gSharedData = gSharedUtility();
This example is clearly broken. It doesn't matter if the code uses multiple threads. It is broken for a single thread.
Soma