[concurrency-interest] AtomicReferenceFieldUpdater vs Unsafe

Joe Bowbeer joe.bowbeer at gmail.com
Mon Nov 28 22:39:39 EST 2011


On Mon, Nov 28, 2011 at 7:08 PM, Vitaly Davidovich wrote:

> Ok I see - you're going by purely what JMM dictates.  In practice though I
> can't imagine a lock() impl that won't issue a fence at some point
> internally before the write.  Therefore I don't see how assignment to x can
> move past it; the expanded lock would look something like:
> - volatile load/acquire
> ...
> - volatile write/cas/etc (assume lock succeeds, as in this example)
> - x = 17
>
> So I still don't understand how, in practice, x = 17 can move above the
> lock.
>

According to the "roach motel" semantics for critical sections, x=17 can
move after the lock in Thread 1, into the "critical section", but it can
never leave the critical section by moving past the unlock.  This is a
transformation that the JIT compiler might perform.

Except in this case there is no unlock in Thread 1...


>  On Nov 28, 2011 9:57 PM, "David Holmes" wrote:
>
>> **
>> The HB edge only arises between an unlock and subsequent lock. Here there
>> is no unlock  in T1 and hence no subsequent lock in T2 and so no HB. (Which
>> is not to say that the necessary memory barriers have not been issued as a
>> side-effect of other things - but there is no HB edge as per the JMM).
>>
>> lock() has acquire semantics as does volatile read, hence regular
>> load/stores can move past them. So here:
>>
>> x = 17;
>> l.lock();
>>
>> can become
>>
>> l.lock();
>> x = 17;
>>
>> which in this case just makes it more likely that T2 would in practice
>> see 17.
>>
>> David
>>
>> -----Original Message-----
>> *From:* Vitaly Davidovich
>> *Sent:* Tuesday, 29 November 2011 12:49 PM
>> *To: *David Holmes
>> *Cc:* Boehm, Hans; concurrency-interest at cs.oswego.edu; Doug Lea
>> *Subject:* RE: [concurrency-interest] AtomicReferenceFieldUpdater vs
>> Unsafe
>>
>> Yes I realized that I misread the snippet right after I sent the email -
>> thanks though :).
>>
>> However doing a tryLock will entail reading a volatile that was set
>> during lock, so shouldn't that provide the HB? Granted I'm talking about a
>> specific impl in the JDK.
>>
>> I don't see how roach motel applies here since the lock() writes a
>> volatile and prior stores can't reorder with it (subsequent ones can move
>> in though).
>> On Nov 28, 2011 9:39 PM, "David Holmes" wrote:
>>
>>> **
>>> Vitaly,
>>>
>>> Thread 2 only reads x if the lock is not available, which means thread 1
>>> must have locked it, which occurs after setting x=17.
>>>
>>> However in terms of happens-before, there is no HB edge here so no
>>> guarantee of x being 17 AFAICS. Thread 2 has to acquire the lock after
>>> thread 1 to get a HB edge that guarantees x == 17. Further, roach-motel
>>> tells us that x=17 could be reordered with the lock() anyway.
>>>
>>> David
>>>
>>> -----Original Message-----
>>> *From:* concurrency-interest-bounces at cs.oswego.edu [mailto:
>>> concurrency-interest-bounces at cs.oswego.edu]*On Behalf Of *Vitaly
>>> Davidovich
>>> *Sent:* Tuesday, 29 November 2011 12:30 PM
>>> *To:* Boehm, Hans
>>> *Cc:* Doug Lea; concurrency-interest at cs.oswego.edu
>>> *Subject:* Re: [concurrency-interest] AtomicReferenceFieldUpdater vs
>>> Unsafe
>>>
>>> Hi Hans,
>>>
>>> In your example why do you say that x should be 17 (or rather, why would
>>> someone assume that)? If thread one writes to x but gets descheduled before
>>> locking, then clearly thread 2 is not guaranteed to read 17; how is this
>>> different from if instead of using a lock, a volatile y was used?
>>>
>>> If thread 1 did lock before tryLock in thread 2 then the store to a
>>> volatile inside lock and a read of that volatile in tryLock should be
>>> sufficient to create the happens-before edge.
>>>
>>> I must be missing your point though.
>>>
>>> Thanks
>>> On Nov 28, 2011 8:23 PM, "Boehm, Hans" wrote:
>>>
>>>> > From: Doug Lea
>>>> >
>>>> > On 11/28/11 14:23, Boehm, Hans wrote:
>>>> > > There's another problem with tryLock()-like methods, which I pointed
>>>> > out in a
>>>> > > 2007 PPoPP paper.  I think the current j.u.c.tryLock() is not
>>>> > correctly
>>>> > > specified.  The problem is illustrated by the following badly
>>>> > designed code:
>>>> > >
>>>> > > Thread 1: x = 17; l.lock();
>>>> > >
>>>> > > Thread 2: while (l.tryLock()) l.unlock(); ... x ...  // x should be
>>>> > 17 here!
>>>> > >
>>>> > >
>>>> > > A solution, more or less adopted by C++11, is to specify tryLock()
>>>> as
>>>> > > allowing spurious failures,
>>>> >
>>>> > I think we are OK on this. The Lock spec defines tryLock in terms
>>>> > of the lock being "available", which means different things
>>>> > across different Lock implementations, and doesn't rule out
>>>> > spurious false returns.
>>>> That interpretation sounds good to me.  It does mean that a lock that
>>>> was constructed before the tryLock call and has never been accessed by
>>>> anything else might not be "available".
>>>>
>>>> Hans
>>>>
>>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20111128/bed5fe0f/attachment.html>


More information about the Concurrency-interest mailing list