Defined Cancellation/Interruption Points
POSIX requires that a set of 25 library functions be cancellation points and that they must be
interruptible should they be blocked at cancellation time. They are required to test for cancellation
even if they don't block. These are functions such as (pthread_cond_wait,
pthread_testcancel, read, sem_wait, write). It allows about 60 more, but leaves it
to the vendor's discretion.
Java faces the same set of issues for its interruptible points, and in JDK 1.2, a set of methods are
defined to throw InterruptedIOException. (They must throw the exception if they have
received an interrupt.) Unfortunately, Java does not specify exactly which functions these are, nor
does it actually require that they throw the exception from the middle of a blocked system call.
Among the calls that do throw InterruptedIOException are read() and accept(),
InterruptedException, catching InterruptedIOException does not clear the interrupt
The Problem with I/O
This problem is even more insidious than it appears at first glance. Not only are the interruption
points not specified, not only are they not required to wake up from blocking calls to throw the
exception, it is not even well defined what happens when they do! In particular, if a thread is
blocked, waiting on a read() from a socket, it is legal for it to read in an unspecified number of
bytes from the socket and then throw InterruptedIOException. This would leave the socket
stream in an undefined state. The only thing that you could do would be to close the socket.
Writes to sockets can also block for an unbounded time if the socket buffer in the kernel fills up.
Typically, this buffer is around 64k, so it's unlikely to fill unless the client is asleep.
Not Cancelling upon Interruption
Interruptions in Java are just exceptions and nothing says that you have to exit a thread simply
because it's been interrupted. For example, you may have a thread running Dungeon Of Doom '99,
which is waiting for the user to vaporize an evil space Dalique (Code Example 9-5). If the user
fails to do so, you may interrupt that thread after 2 seconds and declare him "eliminated," but only
if he's already injured. If you want to use interruption for more than one purpose, you'll need to set
a (protected!) variable to indicate what the interrupted thread should do.
In writing your own libraries, it would be nice to have all of your functions interruption safe. You
can ensure this by never calling any interruptible functions, or by properly handling interruptions
when you do call some. There are a variety of methods for handling this.
You might simply ensure that no interruptions will be sent while your function runs. This requires
a bit of coordination between your libraries and the user of your library to establish a "disabled"
protocol such as that used in Code Example 9-6. You probably don't want to do this, as it binds
your library too close to the application. In Code Example 9-6, the interruptible thread states a
request that no interruptions be sent by setting inCriticalSection to true. That variable
must be protected, of course, and it must be tested at each entry to any code that is either
where this technique is cleaned up a bit.
Search WWH :