[cpp-threads] Implicit Synchronization

Herb Sutter hsutter at microsoft.com
Wed Jul 12 00:34:34 BST 2006


Lawrence wrote:
> > I thought the semantics of store release were for the one
> > variable, not all variables.  Am I wrong?

Not sure what you mean here.

> > That is, given an atomic boolean guarding an integer,
> >
> > global data:    int x = 3; atomic<bool> b = false;
> > thread one:     x = 4;  b = true /* store release */;
> > thread two:     while ( ! b /* load acquire */ ); int y = x;
> >
> > is it that y must be four?

Hans responded:
> Yes.  In this sense it applies to all variables, as it does in Java.

Yes, IMO in any usable model y must be 4, even if x is an ordinary
variable.


Hans continued:
> There is an orthogonal question as to whether any ordering is
guaranteed
> if the two threads access unrelated synchronization objects, e.g.:
> 
> (x, y atomic, assume unordered operations though it doesn't matter
with
> current proposal, initially zero)
> Threads 1:
> x = 1;
> lock(l1); unlock(l1);
> lock(l1); unlock(l1);
> r1 = y;
> 
> Threads 2:
> y = 1;
> lock(l2); unlock(l2);
> lock(l2); unlock(l2);
> r2 = x;
> 
> Can r1 = r2 = 0?
> 
> The original C++ proposal left this up to the library definition.  But
I
> think the answer has to be that this outcome is possible, as it is in
> Java with ordinary, non-volatile variables.

I have two questions. First, leaving atomic<>s aside and assuming x and
y are ordinary variables:

1. I'm assuming that the basic question here about whether lock
coarsening is allowed (eliminating an adjacent unlock/lock pair that
operate on the same lock)? For each thread, I can see that if the locks
are combined, then the other two lines can move into the critical
section and be reordered. I don't see any other way to reorder them if
lock has usual acquire semantics and unlock has usual release semantics.
Am I missing anything important?

Second, assuming that x and y are atomic<> variables:

2. Are you saying that the answer is yes, r1 = r2 = 0 is possible: (a)
if x and y have type atomic<T> and the code is as shown (using normal
assignment)? or (b) only if you explicitly override the default and say
"raw" somewhere on x's/y's types and/or their loads/stores?

I think you must mean (b), right? I think (a) would make atomic<T>
unusable in practice, because either x and y are protected by correct
locks and you don't need atomic<T>, or they aren't and then atomic<T>
would be dangerous because of the non-SC code motion and impossible for
mortals to reason about -- it just seems like there'd be no point in
ever writing atomic<T> if you mean (a) and this surprising result is
really the default behavior.

Herb




More information about the cpp-threads mailing list