-- thread A t <- forkIO $do _ <- accept listener -- blocks
-- thread B killThread t
在Linux上(可能也在OS X和FreeBSD上),但不在Windows上(使用RTS -N4 -RTS等等).
>在这种情况下终止线程A的正确方法是什么?
>有没有一种方式来将线程A分叉到一个特殊的模式,允许终止在它阻止接受的点?
>如果A用forkOS而不是forkIO分叉,会有帮助吗?
我注意到这个错误的Windows行为只有当一个bug report警告.
解决方法
你不能中断阻止外来电话,所以我有点惊讶,你可以在Linux上中断线程.而且,forkOS没有帮助 – 只允许外部代码分配线程本地存储,但与阻止行为无关.但是回想一下接受可以设置为无阻塞:
If no pending connections are present on the queue,and the socket is
not marked as nonblocking,accept() blocks the caller until a
connection is present. If the socket is marked nonblocking and no
pending connections are present on the queue,accept() fails with the
error EAGAIN or EWOULDBLOCK.
这是做什么in the Network library for Posix systems.这样就允许接受中断.
关于Windows的一个有趣的注释:
-- On Windows,our sockets are not put in non-blocking mode (non-blocking -- is not supported for regular file descriptors on Windows,and it would -- be a pain to support it only for sockets). So there are two cases: -- -- - the threaded RTS uses safe calls for socket operations to get -- non-blocking I/O,just like the rest of the I/O library -- -- - with the non-threaded RTS,only some operations on sockets will be -- non-blocking. Reads and writes go through the normal async I/O -- system. accept() uses asyncDoProc so is non-blocking. A handful -- of others (recvFrom,sendFd,recvFd) will block all threads - if this -- is a problem,-threaded is the workaround.
现在,在Windows上接受运行时的线程,使用accept_safe(允许其他线程进行) – 但是它不会将套接字置于非阻塞模式:
accept sock@(MkSocket s family stype protocol status) = do currentStatus <- readMVar status okay <- sIsAcceptable sock if not okay then ioError (userError ("accept: can't perform accept on socket (" ++ (show (family,stype,protocol)) ++") in status " ++ show currentStatus)) else do let sz = sizeOfSockAddrByFamily family allocaBytes sz $\ sockaddr -> do #if defined(mingw32_HOST_OS) && defined(__GLASGOW_HASKELL__) new_sock <- if threaded then with (fromIntegral sz) $\ ptr_len -> throwErrnoIfMinus1Retry "Network.Socket.accept" $ c_accept_safe s sockaddr ptr_len else do paramData <- c_newAcceptParams s (fromIntegral sz) sockaddr rc <- asyncDoProc c_acceptDoProc paramData new_sock <- c_acceptNewSock paramData c_free paramData when (rc /= 0) (ioError (errnoToIOError "Network.Socket.accept" (Errno (fromIntegral rc)) Nothing Nothing)) return new_sock
自2005年以来,在Windows上使用-threaded的版本显式地使用了一个标记为安全的接受调用,允许其他线程取得进展,但不将套接字本身设置为非阻塞模式(因此调用线程阻塞).
要解决它,我看到两个选项:
>制定如何在Windows上进行非阻塞接受呼叫,并修补网络库 – 查看例如snap或yesod在这里,看看他们是否已经解决了.>使用某种监控线程伪造epoll,监控被阻止的子线程进度.