并发 Haskell 异常

Concurrent Haskell exceptions

如何在并发 Haskell 程序中传递异常?

假设我们有一个进程,有多个线程,其中一个正在通过 TCP 连接与某些东西交互,我们得到一个信号(比如在 *nix 系统上)。

这个信号会传递给哪个(绿色)线程?

它会被传送到 "using" 套接字还是 "main" 指定线程将接收并且它必须显式执行 throwTo 以将异常发送到那个(绿色)线程?

POSIX个信号和Haskell个异常之间没有自动对应。

为了将信号转换为异常,需要有一个信号处理程序来执行此操作——向 Haskell 线程之一抛出异常。哪个线程获得异常完全取决于信号处理程序的设置方式。

默认情况下,GHC 仅为 SIGINT 设置这样的处理程序,并且该信号将异常传递给主线程。

你可以install similar handlers for the other signals:

import Control.Concurrent (mkWeakThreadId, myThreadId)
import Control.Exception (Exception(..), throwTo)
import Control.Monad (forM_)
import Data.Typeable (Typeable)
import System.Posix.Signals
import System.Mem.Weak (deRefWeak)

newtype SignalException = SignalException Signal
  deriving (Show, Typeable)
instance Exception SignalException

installSignalHandlers :: IO ()
installSignalHandlers = do
  main_thread_id <- myThreadId
  weak_tid <- mkWeakThreadId main_thread_id
  forM_ [ sigABRT, sigBUS, sigFPE, sigHUP, sigILL, sigQUIT, sigSEGV,
          sigSYS, sigTERM, sigUSR1, sigUSR2, sigXCPU, sigXFSZ ] $ \sig ->
    installHandler sig (Catch $ send_exception weak_tid sig) Nothing
  where
    send_exception weak_tid sig = do
      m <- deRefWeak weak_tid
      case m of
        Nothing  -> return ()
        Just tid -> throwTo tid (toException $ SignalException sig)

main = do
  installSignalHandlers
  ...

但您也可以发挥创意,更改处理程序以将信号传递给其他线程。例如。如果只有一个线程使用套接字,您可以确保该线程获得异常。或者,根据您感兴趣的信号,也许您可​​以 figure out the relevant thread based on the siginfo_t structure(参见 sigaction(2))— 也许是 si_fd 字段?