Haskell在(理论上)不应该出现的情况下陷入僵局

Car*_*ate 7 networking haskell

以下产生死锁错误消息(*异常:线程在MVar操作中无限期阻塞).我一步一步地想到了,我没有看到这个问题.

  • 在主线程上,创建一个MVar,并将其提供给生成器,在新线程上运行
  • 生产者启动,并在listenOn处阻塞,等待连接
  • 主线程继续进入循环,并阻塞,等待MVar接收某些东西
  • 一旦生产者获得连接,它就会继续进入它的循环,并在从套接字接收到某些内容后,将其放入MVar中

意义(据我所知),它应该最终生产者在MVar中放置一些东西,并且主要等待接收某些东西.

如果因为listenOn没有立即连接而卡住了,我怎么能解决这个问题呢?MVar需要在main中创建,并且在生成器分叉之前,它可以传入.

import Control.Concurrent

import Network
import Network.Socket

import System.IO

getSockInfo :: Socket -> IO String
getSockInfo s = do
        info <- getPeerName s
        return $ case info of
            (SockAddrInet port addr) -> "Addr/Port: " ++ (show addr) ++ " / " ++ (show port)
            (SockAddrInet6 port flow addr scope) ->
                "Addr/Port: " ++ (show addr) ++ " / " ++ (show port) ++ "Flow/Scope: " ++ (show flow) ++ " / " ++ (show scope)

producer :: MVar String -> IO ()
producer m = do
    s <- listenOn (PortNumber 5555)
    putStrLn "Listening..."
    info <- getSockInfo s
    putStrLn $ "Connected to " ++ info
    h <- socketToHandle s ReadMode
    loop h m
    where loop h m = do
        message <- hGetLine h
        putMVar m message
        loop h m

main :: IO ()
main = do
    withSocketsDo $ do
        m <- newEmptyMVar
        prod <- forkIO $ producer m
        loop m
        where loop m = do
            n <- takeMVar m
            print n
            loop m
Run Code Online (Sandbox Code Playgroud)

GS *_*ica 4

listenOn立即返回,但不会为您提供已连接的套接字,因此尝试使用它或从中读取会失败。我不确定为什么您没有看到错误消息来表明这一点,因为我在运行您的代码时看到了错误消息。无论如何,监听线程可能此时正在死亡,这使得主线程陷入僵局,因为没有任何东西可以写入 MVar。

使用acceptafterlistenOn等待远程连接应该可以解决这个问题。