[cpp-threads] Visibility question
Boehm, Hans
hans.boehm at hp.com
Wed Aug 2 00:37:50 BST 2006
We agree that there is clearly no race in the fence() case.
But I think that's a fundamentally different question, since in my view
fence() itself introduces synchronization edges between consecutively
executed (in some total order) fence() operations. I think it has to.
Otherwise consider:
Thread 1:
x.store<raw>(1);
fence();
r2 = y.load<raw>();
Thread 2:
y.store<raw>(1);
fence();
r2 = x.load<raw>();
Undesirable outcome: r1 = r2 = 0
There is nothing to prevent this unless something introduces a
synchronization edge between threads to make a store appear "in between"
the initialization and the raw load.
(I suspect there are interesting issues as to what fence() really means
and how it interacts with atomics. But I think the weakest
semi-plausible interpretation is that fences behave as though they are
both load and store operations on some locations shared by all fences.)
The fetch_add operations on the other hand operate on distinct
locations, and hence introduce no inter-thread happens-before edge.
Nonetheless, I'll take this as a vote against calling this a race?
Hans
> -----Original Message-----
> From: cpp-threads-bounces at decadentplace.org.uk
> [mailto:cpp-threads-bounces at decadentplace.org.uk] On Behalf
> Of Peter Dimov
> Sent: Tuesday, August 01, 2006 4:11 PM
> To: C++ threads standardisation
> Subject: Re: [cpp-threads] Visibility question
>
> Boehm, Hans wrote:
> > Clark brought up the following interesting question that I couldn't
> > immediately answer. I think I now have the answer, but I thought I
> > would post it here to make sure we agree.
> >
> > The question is whether "raw", i.e. unordered, atomic operations
> > should contribute to the happens-before relation.
> >
> > As a particular example of what I mean, consider (x,y,z atomic, w
> > ordinary, everything initially zero):
> >
> > Thread 1:
> > w = 1; // ordinary store
> > y.fetch_add<ordered>(1); // ordered atomic; orders
> everything within
> > thread x.store<raw>(1);
> >
> > Thread 2:
> > r2 = x.load<raw>();
> > z.fetch_add<ordered>(1); // ordered atomic; orders
> everything within
> > thread; different variable if (r2) r1 = w; // ordinary load
> >
> > Is there a data race on w?
>
> I believe that the answer should be "no", in the above and in
> the following:
>
> T1:
> w = 1;
> fence();
> x.store<raw>(1);
>
> T2:
> r2 = x.load<raw>();
> fence();
> if (r2) r1 = w; // ordinary load
>
> which is, in turn, a different (potentially less efficient)
> reformulation of
>
> T1:
> w = 1;
> x.store<release>(1);
>
> T2:
> r2 = x.load<acquire>();
> if (r2) r1 = w; // ordinary load
>
> and this is plain as day. :-)
>
> > Thinking about this example a bit more. I'm not 100%
> comfortable with
> > either answer. With the synchronization edge, it's clear
> that ordered
> > atomic updates are not equivalent to the nonatomic version, even if
> > they operate on thread-private data. That's ugly, though
> probably not
> > a showstopper for C++.
>
> Since an <ordered> atomic is a superset of fence(), it seems
> reasonable (to
> me) for it to not be equivalent to an ordinary op even when
> operating on private data.
>
>
> --
> cpp-threads mailing list
> cpp-threads at decadentplace.org.uk
> http://www.decadentplace.org.uk/cgi-bin/mailman/listinfo/cpp-threads
>
More information about the cpp-threads
mailing list