[concurrency-interest] Re: interrupt / notify races even in 6.0beta?

Dawid Kurzyniec dawidk at mathcs.emory.edu
Wed May 17 00:45:09 EDT 2006


Doug Lea wrote:
> Bart Jacobs wrote:
>>
>> So it seems it would help if the JLS clarified the meaning of "while 
>> waiting" (both for 17.8.1 and 17.8.4), by saying that the thread 
>> "stops waiting" sometime after the notify()/interrupt() call, and 
>> therefore is still considered to "be waiting" until such time.
>>
>
> Yes; this is a good idea.
>
> The effects seen here might seem less mysterious if you know
> the basic implementation scheme, which is typically the one
> documented for AbstractQueuedSynchronizer.Condition.await; see
> http://gee.cs.oswego.edu/dl/jsr166/dist/docs/java/util/concurrent/locks/AbstractQueuedSynchronizer.ConditionObject.html 
>
>
>        1. If current thread is interrupted, throw InterruptedException
>        2. Save lock state returned by 
> AbstractQueuedSynchronizer.getState()
>        3. Invoke AbstractQueuedSynchronizer.release(int) with saved 
> state as argument, throwing IllegalMonitorStateException if it fails.
>        4. Block until signalled or interrupted
>        5. Reacquire by invoking specialized version of 
> AbstractQueuedSynchronizer.acquire(int) with saved state as argument.
>        6. If interrupted while blocked in step 4, throw exception
>
>
> Notice that interrupt status is checked (at least) twice -- on entry, 
> and then
> again during/after an OS-level blocking.
>
> This means that response to (notify; interrupt) or (interrupt; notify)
> can go either way, depending on whether each came at/before
> step 1, or step 4, or later. So even though in the test programs
> here, the caller "knows" which came first, it cannot control the
> points at which the waiting thread is paying attention to which of these
> events.
>

I guess in this particular case we're only talking about the 
interruption during OS-level blocking in step 4.

I realize that you (EG) have dealt with this issue for decades now; so 
please have a little patience with me here; I'd like to understand the 
problem fully to make sure that I don't screw up anything in the 
backport. It is no mystery that there is a possible race between notify 
/ interrupt, as it is between memory read / write, when there is no 
happens-before relationship between these operations. Ideally, and 
intuitively however, I would expect that the ordering of notify / 
interrupt becomes deterministic when there is a happens-before 
relationship, e.g. if the operations are invoked from the same thread. 
Apparently, it is not the case, and the spec does not actually promise 
it. I am trying to understand why it can't be made to be the case. For 
instance, why can't the interruption status be combined with a thread 
state (runnable, blocked, waiting, io) into an atomic state variable - 
having interrupt() CAS-ing it to INTERRUPTED, removing the tread from 
the condition's wait set if was WAITING, and having notify() loop 
CAS-ing the state of a candidate thread to RUNNABLE if was WAITING, and 
skipping it over if was INTERRUPTED. Perhaps the problem is that the OS 
layer does not expose things this way?... But then again, with the 
low-level primitives like those used by park/unpark, wouldn't it be 
possible to implement it at the JVM side, without relying on OS-level 
wait sets etc?

In any case, since the ordering is not deterministic, the aforementioned 
ReentrantLock unit test is probably too strict. Would a Thread.yield() 
or a delay inserted between interrupt and notify be a reasonable fix?...

Regards,
Dawid



More information about the Concurrency-interest mailing list