[concurrency-interest] Re: interrupt / notify races even in
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
> 1. If current thread is interrupted, throw InterruptedException
> 2. Save lock state returned by
> 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
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?...
More information about the Concurrency-interest