Improving the speed of Thread interrupt checking
Charles Oliver Nutter
headius at headius.com
Sat May 11 01:51:33 PDT 2013
An addendum:
thread.interrupt *does* have other side effects, like breaking out of
blocking IO operations. However, it still doesn't matter; you can mutex to
try to guarantee that the IO interrupt and setting the bit happen
atomically, but by being in blocking IO you already know the thread is not
running. A different sequence:
* Thread A performs a blocking IO operation and gets stuck.
* Thread B attempts to interrupt it
* Thread B acquires the lock, sets interrupt bit, and wakes A out of IO
* Thread A wakes up and interrupt bit is set. It is retrieved, cleared, and
handled as true
But...
* Thread A performs a blocking IO operation and gets stuck.
* Thread B attempts to interrupt it
* Thread A wakes out of blocking IO, sees interrupt bit is not set, and
proceeds
* Thread B acquires the lock
* Thread A ultimately handles the interrupt as false
Now, depending on when B decides to proceed with actually interrupting
blocking IO, A may have already stopped blocking and B might not see
that...unless all interruptible blocking IO operations *also* acquire the
interrupt mutex. But that doesn't work either; B can't acquire the
interrupt mutex if A is holding it and blocking. If A releases the mutex
upon blocking and tries to acquire it immediately after, we're back to
square one...B may not see that A has completed blocking because A can't
return from a blocking operation and acquire the mutex atomically, and B
can't acquire the mutex and check blocking status atomically.
It seems like you can't make any guarantees here either, even with locks.
- Charlie
On Sat, May 11, 2013 at 3:26 AM, Charles Oliver Nutter
<headius at headius.com>wrote:
> On Sat, May 11, 2013 at 2:49 AM, Jeroen Frijters <jeroen at sumatra.nl>wrote:
>
>> I believe Thread.interrupted() and Thread.isInterrupted() can both be
>> implemented without a lock or CAS.
>>
>> Here are correct implementations:
>>
> ...
>
>> Any interrupts that happen before we clear the flag are duplicates that
>> we can ignore and any that happen after are new ones that will be returned
>> by a subsequent call. The key insight is that the interruptPending flag can
>> be set by any thread, but it can only be cleared by the thread it applies
>> to.
>>
>
> This may indeed be the case. My goal with considering CAS was to maintain
> the full behavioral constraints of the existing implementation, which will
> never clear multiple interrupts at once, regardless of duplication.
>
> If your assumption holds, then Vitaly's case is not a concern. His case,
> again:
>
> * Thread A retrieves interrupt status
> * Thread B sets interrupt, but cannot clear it from outside of thread A
> * Thread A clears interrupt
>
> The end result of this sequence is indeed different if A's get + clear are
> not atomic: the interrupt status after A returns would be clear rather than
> set. However, *it does not really matter*.
>
> If we look at the *caller* of the interrupt checking, things become
> obvious.
>
> Mutexed/atomic version:
>
> * Thread A makes a call to Thread.interrupt to get and clear interrupt
> status
> * Thread A acquires lock and gets interrupt status and clears it atomically
> * Thread A returns from Thread.interrupt, reporting that the thread was
> interrupted, and the caller knows it has been cleared
> * Before Thread A proceeds any further (raising an error, etc), thread B
> comes in and sets interrupt status.
>
> The result is that the interrupt is set, and there's nothing A can do to
> ensure it has been cleared. A subsequent call to Thread.interrupted can be
> preempted *after* the clear anyway.
>
> So, a different preemption order with mutex:
>
> * Thread A makes a call to Thread.interrupt to get and clear interrupt
> status
> * Before the mutex is acquired, Thread B swoops in, setting interrupt
> status.
> * Thread A proceeds to acquire mutex and only sees a single interrupt bit;
> it gets status and clears it.
>
> So even an atomic version does nothing to guarantee what the interrupt
> status will be after all threads are finished fiddling with the interrupt
> bit; preemption can happen before or after the mutexed operation, producing
> different results in both cases.
>
> Ultimately, this may actually be a flaw with the way Thread interrupt
> works in the JVM. If there's potential for interrupt to be set twice or
> more, the interrupted thread can't ever guarantee that the interrupt has
> been cleared.
>
> In practice, this flaw may not matter; if you have one or more external
> threads that interrupt a target thread N times, you have to assume (and
> have always had to assume) the target thread will see anywhere from 1 to N
> of those interrupts, depending on preemption. This does not change with any
> of the proposed implementations. The only safe situation is when you know
> interruption will happen only once within a critical section of code.
>
> Put simply (tl;dr): even with atomic/mutexed interrupt set+clear, you
> can't make any guarantees about how many interrupts will be seen if
> multiple interrupts are attempted. If true, the mutex in the current
> implementation is 100% useless.
>
> - Charlie
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/mlvm-dev/attachments/20130511/bd659209/attachment.html
More information about the mlvm-dev
mailing list