Using TChan with Timeout

前端 未结 1 1010
臣服心动
臣服心动 2021-02-14 19:49

I have a TChan as input for a thread which should behave like this:

If sombody writes to the TChan within a specific time, the content should be retrieved. If there is n

相关标签:
1条回答
  • 2021-02-14 20:07

    Use registerDelay, an STM function, to signal a TVar when the timeout is reached. You can then use the orElse function or the Alternative operator <|> to select between the next TChan value or the timeout.

    import Control.Applicative
    import Control.Monad
    import Control.Concurrent
    import Control.Concurrent.STM
    import System.Random
    
    -- write random values after a random delay
    packetWriter :: Int -> TChan Int -> IO ()
    packetWriter maxDelay chan = do
      let xs = randomRs (10000 :: Int, maxDelay + 50000) (mkStdGen 24036583)
      forM_ xs $ \ x -> do
        threadDelay x
        atomically $ writeTChan chan x
    
    -- block (retry) until the delay TVar is set to True
    fini :: TVar Bool -> STM ()
    fini = check <=< readTVar
    
    -- Read the next value from a TChan or timeout
    readTChanTimeout :: Int -> TChan a -> IO (Maybe a)
    readTChanTimeout timeoutAfter pktChannel = do
      delay <- registerDelay timeoutAfter
      atomically $
            Just <$> readTChan pktChannel
        <|> Nothing <$ fini delay
    
    -- | Print packets until a timeout is reached
    readLoop :: Show a => Int -> TChan a -> IO ()
    readLoop timeoutAfter pktChannel = do
      res <- readTChanTimeout timeoutAfter pktChannel
      case res of
        Nothing -> putStrLn "timeout"
        Just val -> do
          putStrLn $ "packet: " ++ show val
          readLoop timeoutAfter pktChannel
    
    main :: IO ()
    main = do
      let timeoutAfter = 1000000
    
      -- spin up a packet writer simulation
      pktChannel <- newTChanIO
      tid <- forkIO $ packetWriter timeoutAfter pktChannel
    
      readLoop timeoutAfter pktChannel
    
      killThread tid
    
    0 讨论(0)
提交回复
热议问题