并发的Haskell异常

22

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

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

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

它会被传递给正在“使用”套接字的那个线程,还是主要指定的“主”线程将接收并且必须显式执行throwTo来将异常发送到该(绿色)线程?


6
S. Marlow的《Haskell并行与并发编程》第8章至少部分涵盖了该主题。 - palik
1
GHC维基上的“运行时信号处理”页面也是相关的 https://ghc.haskell.org/trac/ghc/wiki/Commentary/Rts/Signals AsyncException类型的文档提供了有关哪些线程可以成为特定异常目标的一些信息。https://hackage.haskell.org/package/base-4.10.1.0/docs/Control-Exception.html#t:AsyncException - danidiaz
1
这似乎是安装SIGINT顶级处理程序的代码片段:https://github.com/ghc/ghc/blob/7b52525ecb2a09b21e7e5393f45a72ed1dfa3bc8/libraries/base/GHC/TopHandler.hs#L87 我们可以看到UserInterrupt被抛到主线程。 - danidiaz
1个回答

1

POSIX信号与Haskell异常之间没有自动对应关系。

为了将信号转换为异常,需要有一个信号处理程序来实现这一点——向Haskell线程之一抛出异常。哪个线程收到异常完全取决于信号处理程序的设置方式。

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

您可以安装其他信号的类似处理程序

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
  ...

但你也可以发挥创意,更改处理程序以将信号传递到其他线程。例如,如果只有一个线程正在使用套接字,则可以确保该线程获得异常。或者,根据您感兴趣的信号,也许您可以根据siginfo_t结构找出相关线程(参见sigaction(2))——也许是si_fd字段?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接