RE: Concurrent Haskell, asynchronous exceptions and interruptibility (again)

For Concurrent Haskell, with respect to asynchronous exceptions, can a thread receive an asynchronous exception if it's evaluating an expression that could "potentially block on IO" when evaluated within the "block" function?
Specifically, is interruptibility determined statically in the language definition or dynamically at run time?
"dynamically at runtime", according to the semantics given in our paper. GHC does actually implement this, although it implements a slightly different version of throwTo from the one described in the paper (ours blocks until the exception has been delivered).
For example, assume a thread is evaluating the following function.
transfer :: MVar a -> IO (MVar a) transfer from = block $ do to <- newEmptyMVar x <- takeMVar from putMVar to x return to
In general, since putMVar is an IO function, it can potentially block (if its MVar argument is already occupied with a value). However, since "MVar to" will obviously be vacant in this instance, the putMVar can not block on IO.
Would ghc allow an asynchronous exception to be raised at the point that "putMVar to x" is evaluated?
Not unless the putMVar blocks. The proof that it never blocks depends on the behaviour of other threads though: if you have another thread doing putMVar on the same MVar, then it may block. Other threads must be "well-behaved" for it to work.
If not, then I guess transfer is exception safe.
Would that answer scale? Could I replace the "putMVar to x" with an arbitrarily large/complex IO function that I might write that is guaranteed (by me at least) to be non-blocking and still be sure that an exception would not be delivered during evaluation of that function?
Yes. Cheers, Simon

On Wednesday 30 October 2002 01:20 am, Simon Marlow wrote:
Not unless the putMVar blocks. The proof that it never blocks depends on the behaviour of other threads though: if you have another thread doing putMVar on the same MVar, then it may block. Other threads must be "well-behaved" for it to work.
At first glance, this seems like an untenable situation, but it's not really. The mechanisms provided in GHC are quite low-level. Careful design of higher-level combinators (implemented in terms of block/unblock, etc.) appropriate to the problem at hand is essential. If all of threads use the high-level combinators, you can guarantee that they're all well-behaved. A common idiom is the "with<Resource>" style of combinator. Here's withSocket, which guarantees that the socket will be closed at the end of the withSocket, even if the thread using it is killed: withSocket :: Socket -> (Socket -> IO a) -> IO a withSocket sock ioa = finally (ioa sock) (sClose sock) A similar idea works for shared resources; see Control.Concurrent.MVar.withMVar for the classic example. It changes the way your code looks pretty dramatically, but it makes the job of debugging multi-threaded, multi-process programs much easier. Cheers, Andy -- Andy Moran Galois Connections Inc. Fax. (503) 350 0833 3875 SW Hall Blvd. http://www.galois.com Beaverton, OR 97005 moran@galois.com
participants (2)
-
Andrew Moran
-
Simon Marlow