【发布时间】:2018-12-09 08:10:54
【问题描述】:
如何根据存储在 MVar 中的一些可变状态有条件地在给定线程中包装 IO 操作?
我的总体目标是启用超时,以便在给定的游戏中,如果玩家没有在 30 秒内向服务器发送操作,那么套接字消息回调将被调用,并带有一个特殊的超时操作,以表示玩家未能行动。
我正在寻找一种方法,使每个套接字线程能够订阅 MVar 中包含的游戏状态更改。
我目前创建超时操作的实施草案如下:
-- This function processes msgs from authenticated clients
authenticatedMsgLoop ::
(MsgIn -> ReaderT MsgHandlerConfig (ExceptT Err IO) ())
-> MsgHandlerConfig
-> IO ()
authenticatedMsgLoop msgCallback msgHandlerConfig@MsgHandlerConfig {..}
= do
finally
(forever $ do
maybeMsg <- timeout 1000000 (WS.receiveData clientConn)
let parsedMsg = maybe (Just Timeout) parseMsgFromJSON maybeMsg
for_ parsedMsg $ \parsedMsg -> do
result <-
runExceptT $ runReaderT (msgCallback parsedMsg) msgHandlerConfig
either (\err -> sendMsg clientConn $ ErrMsg err) return result)
return ())
(removeClient username serverState)
总结所有有效的消息都传递给 msgCallback 函数。然后,此回调将使用新的玩家操作更新纸牌游戏,然后将新的游戏状态广播给所有订阅该游戏的客户端。
这样做的一个问题是,一旦发生超时,就会在线程内引发异常,从而断开正在运行的套接字。这当然是不受欢迎的行为。
另一个问题是,此超时是在客户端收到新消息后实现的。相反,我希望仅在游戏处于特定状态时才实施超时 - 在这种状态下,此特定线程所代表的玩家是下一个要采取行动的玩家。
因此,特定游戏中玩家动作的超时只能同时在最多一个线程中执行。由于纸牌游戏采用回合制动作。
因此,我需要根据存储在 MVar 中的游戏状态,有条件地包装用于接收超时消息的 IO 操作。
【问题讨论】:
-
听起来 STM 会让实现变得更容易。请参阅此答案以处理超时stackoverflow.com/questions/22171895/using-tchan-with-timeout
标签: multithreading sockets haskell concurrency