在并发的Haskell程序中,异常是如何传递的?
假设我们有一个进程,其中有多个线程,其中一个线程正在通过TCP连接与某些内容交互,然后我们收到了一个信号(比如在*nix系统上)。
这个信号会被传递给哪个(绿色)线程?
它会被传递给正在“使用”套接字的那个线程,还是主要指定的“主”线程将接收并且必须显式执行throwTo
来将异常发送到该(绿色)线程?
在并发的Haskell程序中,异常是如何传递的?
假设我们有一个进程,其中有多个线程,其中一个线程正在通过TCP连接与某些内容交互,然后我们收到了一个信号(比如在*nix系统上)。
这个信号会被传递给哪个(绿色)线程?
它会被传递给正在“使用”套接字的那个线程,还是主要指定的“主”线程将接收并且必须显式执行throwTo
来将异常发送到该(绿色)线程?
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字段?
AsyncException
类型的文档提供了有关哪些线程可以成为特定异常目标的一些信息。https://hackage.haskell.org/package/base-4.10.1.0/docs/Control-Exception.html#t:AsyncException - danidiazUserInterrupt
被抛到主线程。 - danidiaz