How do you subscribe to state changes across threads?

Multi tool use
How do you subscribe to state changes across threads?
How do you conditionally wrap an IO action in a given thread depending on some mutable state stored in an MVar?
My overall aim is to enable timeouts so that in a given game if a player does not send an action to the server within 30 seconds then the socket msg callback will be called with a special Timeout action to denote failure of the player to act.
I am looking for a method to enable each socket thread to subscribe to a change in game state contained in an MVar.
My current draft implementation for creating a Timeout action is as follows:
-- 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)
To summarise all msgs which are valid are passed to the msgCallback function. This callback will then update the card game with the new player action and then broadcast the new game state to all clients who are subscribed to the game.
One issue with this is that as soon as a timeout occurs an exception is thrown inside the thread which disconnects the running socket. This is of course undesirable behaviour.
Another issue is that this timeout is implemented after a new msg is received by a client. Instead I would like to the timeout to only be implemented when the game is in a particular state - that is a state in which the player represented by this particular thread is the next player to act.
Therefore the timeout for a player action in a particular game can only be enacted in at most one thread at at the same time. As the card game employs turn based action.
It follows that I need to conditionally wrap the IO action for receiving messages with a timeout depending on the game state which is stored within an MVar.
1 Answer
1
I would use a Chan or TChan to subscribe each thread to the game state. When the state changes, I would check whether the current player is the same as the thread player. Then either return to awaiting the next message on the TChan
or start the timer for user input.
TChan
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
It sounds like STM would make the implementation much easier. See this answer for dealing with timeouts stackoverflow.com/questions/22171895/using-tchan-with-timeout
– jberryman
Jun 30 at 19:01