Haskell async and cancel
I was asked to help debug the following code. It’s a simple example meant to be added to a bigger system. There are multiple asynchronous bits of code that update a value, but only one should be completed, furthermore a user event can override the other events. I was not clear on all the details, but the code I was given looked like this.
module Main where
import Control.Concurrent (threadDelay)
import Control.Concurrent.Async
main = do
continuous <- async $ do
threadDelay $ (6 * 10 ^ (6 :: Int))
print ("continuous" :: String)
userEvent <- async $ do
print ("userEvent" :: String)
uninterruptibleCancel continuous
print ("pre-waitAnyCancel" :: String)
_ <- waitAnyCancel [continuous, userEvent]
print ("post-waitAnyCancel" :: String)
The output looks like this.
$> stack runghc Main.hs
"userE"vpernet-"w
aitAnyCancel"
Main.hs: thread killed
The mixed output from multiple threads is normal, but I was not expecting Main.hs: thread killed
. After trying out various functions from the async
library, I was able to make it run with _ <- waitAnyCatchCancel [continuous, userEvent]
. This cancels the other operations, but it also catches any errors.
We did not realize that cancel
works by throwing an error. That is what caused the first version to crash. The Hackage documentation states it clearly:
Cancel an asynchronous action by throwing the ThreadKilled exception to it, and
waiting for the Async thread to quit.