[cpp-threads] Counter strawman proposal :-)
Peter Dimov
pdimov at mmltd.net
Sat Jul 2 11:58:16 BST 2005
Boehm, Hans wrote:
> After a long pause ...
>
> Peter -
>
> This seems to be much closer to happens-before consistency in Java
> than what we have been discussing. It no longer invokes undefined
> behavior if there are races, and assumes there is an "accessed value".
> Is that intentional?
Yes, matches existing practice and accomodates atomic reads easily.
> With this approach
>
> r1 = x;
> if (r1 != (<stuff that doesn't touch r1>, r1) abort();
>
> is guaranteed not to abort.
I'm not sure that I understand the example... is r1 visible to other
threads? If it is, the example may abort if there is a race. If not, it
cannot abort.
> That means that compilers can
> no longer reload registers that have been spilled with their
> original values, even if they are known not to have been modified.
If your r1 was supposed to represent a register, then no. In the original
C++ code:
if( x != (..., x) ) abort();
the two 'x' expressions may yield different values if there is a race,
regardless of whether there are registers involved in the generated machine
code.
If you specifically introduce a local variable r1 that is invisible to other
threads, the compiler no longer can reload it from x, yes. It will have to
spill it into temporary storage.
>> If two or more modifications that yield distinct values are
>> _potentially
>> visible_, the accessed value is unspecified. Note that the
>> accessed value is
>> not guaranteed to match any of the potentially visible values.
>
> I think we want to just invoke undefined behavior here.
Perhaps we do. :-)
>> - O1 _synchronizes with_ O2, or
>>
>> - there _exists an ordering constraint between_ O2 and O1.
>
> Why do you separate these?
This is a sketch. "synchronizes with" is supposed to cover pthread_create,
pthread_join and mutex locks. But the specification isn't quite right this
way, so in its final form these would probably need to be described under
"ordering constraints", too.
>> There _exists an ordering constraint between_ O1 and O2 when:
>>
>> - a sink-(O1 type) barrier _occurs after_ O1 in its thread, and
>> - a hoist-(O2 type) barrier _occurs before_ O2 in its thread, and
>> - the first barrier precedes the second barrier in the
>> program execution.
>
> This assumes a total ordering on "barriers"? I thought we wanted
> to accommodate the fact that a release store followed by an acquire
> load have no visibility ordering between them?
I'll have to think about this question a bit. Depending on how the above is
interpreted, it does seem that it either imposes a total ordering, or too
little ordering. In:
T1: store.rel( x, 1 );
T2: if( load.acq( x ) == 1 ) assert( load.acq( x ) == 1 );
the second load is not guaranteed to see 1, because the sink-* barrier does
not occur after itself.
Very tricky.
More information about the cpp-threads
mailing list