Предполагается, что функция withTimeout
передает ConsoleEvent
сообщение CeTimeout
каждые s :: Int
секунды, если ничего не было получено. Вместо этого ему не удается отправить события CeTimeout
в нужное время. Одно событие CeTimeout
заменяется другими событиями, если прошло более s
секунд с потерей исходного события. Также вместо одного CeTimeout
события должно быть n*s
CeTimeout
событий с n
подсчетом на каждый прошедший s
секундный период. Где ошибка и что можно исправить? Спасибо!
withTimeout :: (MonadIO t) => Int -> Pipe ConsoleEvent ConsoleEvent t ()
withTimeout ((* 1000000) -> s) = join . liftIO $ work
where
work :: (MonadIO t) => IO (Pipe ConsoleEvent ConsoleEvent t ())
work =
do
(oSent, iKept) <- spawn $ bounded 1
(oKept, iSent) <- spawn $ unbounded
(oTimeout, iTimeout) <- spawn $ bounded 1
tid <- launchTimeout oTimeout >>= newMVar
forkIO $ do
runEffect . forever $ fromInput iKept >-> factorTimeout tid oTimeout >-> toOutput oKept
forkIO $ do
runEffect . forever $ fromInput iTimeout >-> toOutput oKept
return $ do
await >>= (liftIO . guardedSend oSent)
(liftIO . guardedRecv $ iSent) >>= yield
guardedSend :: Output ConsoleEvent -> ConsoleEvent -> IO ()
guardedSend o ce =
(atomically $ send o ce) >>= \case
True -> return ()
otherwise -> die $ "withTimeout can not send"
guardedRecv :: Input ConsoleEvent -> IO ConsoleEvent
guardedRecv i =
(atomically $ recv i) >>= \case
Just a -> return a
otherwise -> die $ "withTimeout can not recv"
launchTimeout :: Output ConsoleEvent -> IO ThreadId
launchTimeout o =
forkIO . forever $ do
threadDelay $ s
(atomically $ send o CeTimeout) >>= \case
True -> return ()
otherwise -> die "withTimeout can not send timeout"
relaunchTimeout :: Output ConsoleEvent -> ThreadId -> IO ThreadId
relaunchTimeout o oldTid =
do
tid <- launchTimeout o
killThread oldTid
return tid
factorTimeout :: MVar ThreadId -> Output ConsoleEvent -> Pipe ConsoleEvent ConsoleEvent IO ()
factorTimeout v o =
do
ce <- await
liftIO . modifyMVar_ v $ relaunchTimeout o
yield ce
Вот полностью исполняемый скрипт.
(i, o)
внутриwithTimeout
вместо того, чтобы отправлять тайм-аутыi
, сгенерированному вmain
? - person Li-yao Xia   schedule 01.10.2018launchTimeout
сразу после завершения потока тайм-аута, но единственным потребителем являетсяceRecv
, который собирается удалить только что отправленноеfactorTimeout
событие. Когда второй поток тайм-аута пытается отправить тайм-аут, другой конец может быть подвергнут сборке мусора, поэтому вывод запечатывается, и вы получаете ошибку. - person Li-yao Xia   schedule 01.10.2018