I'm trying to understand the difference between cancel and uninterruptibleCancel from the Control.Concurent.Async package. I believe it has something to do with the underlying concepts of mask , uninterruptibleMask, and interruptible operations. Here's what I have understood so for:
throwTo does. In some way, this can also be considered as a form of inter-thread communication.try / catch around certain operations and expects/handles only certain exceptions. But, Asynchronous exceptions can be delivered when the target thread could be at any point in the execution.mask allows use to protect critical sections in the target/receiving thread from delivery of asynchronous exceptions. The operation protected by mask doesn't need to deal with asynchronous-exceptions till the point it calls restore.At this point uninterruptibleMask comes into the picture, and I start losing the plot. I thought the whole point of mask was to NOT deliver asynchronous-exceptions while executing a protected piece of code. However, here is what the docs say about "interruptible actions":
It is useful to think of mask not as a way to completely prevent asynchronous exceptions, but as a way to switch from asynchronous mode to polling mode. The main difficulty with asynchronous exceptions is that they normally can occur anywhere, but within a mask an asynchronous exception is only raised by operations that are interruptible (or call other interruptible operations). In many cases these operations may themselves raise exceptions, such as I/O errors, so the caller will usually be prepared to handle exceptions arising from the operation anyway. To perform an explicit poll for asynchronous exceptions inside mask, use allowInterrupt.
mask, if there are some points where it is safe to handle asynchronous-exceptions, one can call allowInterrupt. This implicitly means, that, unless allowInterrupt is called, asynchronous exceptions will NOT be delivered while executing masked code. What, then, is the purpose of uninterruptibleMask?uninterruptibleCancel? IIUC, thread A is trying to cancel thread B, but thread A, itself, is trying to protect itself from some sort of asynchronous exceptions, which may possibly be initiated by a third thread C, right? In the code for cancel (given below), which part is so critical that it needs the ultimate form of protection from asynchronous exceptions? Isn't throwTo an atomic/masked operation itself? Further, even if an asynchronous-exception is delivered to thread-A while executing waitCatch, what difference does it make? Actually, if I think about it, why do we need to even mask this code in the first place (let alone, uninterruptibleMask) ?cancel a@(Async t _) = throwTo t AsyncCancelled <* waitCatch a
Under no masking, asynchronous exceptions can happen wherever. Under mask, asynchronous exceptions can only appear from interruptible actions (which are generally blocking). Under uninterruptibleMask, asynchronous exceptions are completely out of the picture. Also, please note that allowInterrupt is just one of the interruptible actions; there are a ton more, e.g. takeMVar. With just mask, it is e.g. impossible to block on an MVar without opening yourself up to exceptions, but uninterruptibleMask lets you do it (though you shouldn't).
uninterruptibleCancel is useful because cancel waits for the target thread to finish. This is a blocking operation, so, as is convention, it is also interruptible. Thus, when you use cancel, you open yourself up to receiving unexpected exceptions, whether you are masked or not. When you use uninterruptibleCancel, you are 100% guaranteed to not get an exception. That's it. Remember that exceptions are non-local; even if nothing in cancel is critical, leaving it unprotected means an exception can leak into something that is.
mask $ do
cancel something -- whoops, this can receive an exception, even though it's masked
someCleanup -- therefore this might not get called
vs.
mask $ do
uninterruptibleCancel something -- no exceptions
someCleanup -- so this will definitely happen (assuming the target thread ends)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With