我正在尝试使用Haskell创建一个简单的服务器。当客户端连接到服务器时,服务器会记录其地址。服务器发送广播时每 n 微秒。
这是服务器
data Server = Server {
sSocket :: Socket,
sPort :: Port,
sClients :: MVar [ClientAddress]
}
(注意允许从多个线程使用客户端的MVar。)
这是创建服务器的方式
startServer port = withSocketsDo $ do
socket <- listenOn $ PortNumber $ fromIntegral port
clients <- newEmptyMVar
let server = Server socket port clients
forkIO $ forever $ accept socket >>= forkIO . (handleClientRequest server)
forever $ updateClients server 1000000
服务器使用其线程并分叉另一个。分叉线程处理任何传入的客户端请求
handleClientRequest server client = do
clients <- takeMVar $ sClients server
putMVar (sClients server) (client : clients)
并使用updateClients
函数
updateClients server frequency = do
putStrLn "1"
clients <- (takeMVar $ sClients server)
putStrLn "2"
putStrLn $ show $ length clients
threadDelay frequency
我遇到的问题是&#34; 2&#34;永远不会打印到屏幕上。我相信这是因为takeMVar
中的updateClients
行永远不会完成。
为什么会冻结?
答案 0 :(得分:5)
你从一个空的MVar开始,所以takeMVar
永远阻止。尝试使用newMVar []
代替newEmptyMVar
,可能是这样的:
startServer port = withSocketsDo $ do
socket <- listenOn $ PortNumber $ fromIntegral port
clients <- newMVar []
let server = Server socket port clients
forkIO $ forever $ accept socket >>= forkIO . (handleClientRequest server)
forever $ updateClients server 1000000
现在,MVar总是满的,除非客户实际修改它。
当您使用MVar来保护关键部分时,考虑正常状态是有帮助的;在这种情况下,它是一个客户列表。 MVar应该为空的唯一时间是客户端实际修改状态时,所以如果你可以使用modifyMVar
并设置初始状态,那么你的代码应该没有死锁。
此外,如果您可以使用withMVar
而不是takeMVar/putMVar
,则应该这样做,因为如果出现异步异常,它会使MVar保持一致状态。