下面的函数要么接收并确认要么等到它的到期时间到来并返回。
现在,它在接收和确认时有效。当没有收到确认时它会正常工作并等到适当的时间。
到达到期时间时冻结。似乎它没有正确退出我的自构造循环。我也试过if-then-else,但结果相同。我不想使用whileM。
如何正确退出循环?
import Network.Socket hiding (send, sendTo, recv, recvFrom)
import Network.Socket.ByteString
waitAck s duetime' = do
print ("in")
(a, _) <- recvFrom s 4711
now' <- getPOSIXTime
unless (B.unpack a == "ack") (when (now' < duetime') (waitAck s duetime'))
print (B.unpack a)
return ()
答案 0 :(得分:4)
正确的解决方案是竞争两个线程,一个等待确认,一个等待时间。杀死失去种族的人。也许这个(未经测试的)代码会给你一个关于如何:
的提示import Control.Concurrency.MVar
withTimeout :: Int -> IO a -> IO (Maybe a)
withTimeout n io = do
mvar <- newEmptyMVar
timeout <- forkIO (threadDelay n >> putMVar mvar Nothing)
action <- forkIO (io >>= putMVar mvar . Just)
result <- takeMVar mvar
killThread timeout
killThread action
return result
waitAck s timeout = withTimeout timeout go where
go = do
(a, _) <- recvFrom s 4711
if B.unpack a == "ack" then print (B.unpack a) else go
编辑:似乎base
提供System.Timeout.timeout就是为了这个目的。它的实现也比这个更正确。
答案 1 :(得分:1)
这不是一个迭代循环。在递归调用之后,你不会在这些东西上放置任何条件,所以当条件最终失败时,整个事情将展开,为每次递归调用打印一次。我怀疑这可能足以使它显得冷冻。
尝试这样的事情:
waitAck s duetime' = do
print ("in")
(a, _) <- recvFrom s 4711
now' <- getPOSIXTime
if B.unpack a == "ack" || now' >= duetime'
then print (B.unpack a)
else waitAck s duetime'