【问题标题】:How do you subscribe to state changes across threads?您如何订阅跨线程的状态更改?
【发布时间】: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 操作。

【问题讨论】:

标签: multithreading sockets haskell concurrency


【解决方案1】:

我会使用Chan 或TChan 为每个线程订阅游戏状态。当状态发生变化时,我会检查当前播放器是否与线程播放器相同。然后要么返回等待TChan 上的下一条消息,要么启动计时器以供用户输入。

【讨论】:

    猜你喜欢
    • 2022-10-05
    • 1970-01-01
    • 2020-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多