您如何订阅各个线程的状态更改?

时间:2018-06-30 09:05:35

标签: multithreading sockets haskell concurrency

如何根据MVar中存储的某些可变状态有条件地将IO操作包装到给定线程中?

我的总体目标是启用超时功能,以便在给定游戏中,如果玩家未在30秒内向服务器发送动作,则套接字msg回调将被调用,并带有特殊的Timeout动作来表示玩家失败。行动。

我正在寻找一种方法,使每个套接字线程能够订阅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)

总结一下,所有有效的msg都传递给msgCallback函数。然后,该回调将使用新的玩家操作更新纸牌游戏,然后将新的游戏状态广播给所有订阅该游戏的客户端。

与此有关的一个问题是,一旦发生超时,就会在线程内引发异常,从而使正在运行的套接字断开连接。当然,这是不受欢迎的行为。

另一个问题是,此超时是在客户端收到新的消息后实现的。相反,我希望仅在游戏处于特定状态时才执行超时,在该状态下,该特定线程代表的玩家是下一个要行动的玩家。

因此,特定游戏中玩家行为的超时只能同时在最多一个线程中进行。由于纸牌游戏采用回合制动作。

接下来,我需要根据MVar中存储的游戏状态,有条件地包装IO操作以接收带有超时的消息。

1 个答案:

答案 0 :(得分:1)

我将使用ChanTChan将每个线程订阅到游戏状态。当状态改变时,我将检查当前播放器是否与线程播放器相同。然后返回TChan上等待下一条消息,或者启动计时器以供用户输入。