2012-03-05 129 views
1

下面的函数想要接收和确认,或者等到其到期时间到来并返回。循环未终止

现在,它收到并确认后就能正常工作。当没有收到确认时它会正常工作并等待到期。

当到期时间结束。它似乎没有正确退出我自己构建的循环。我也尝试过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

所以,你检查'duetime''是你已经收到了一些数据后唯一的一次 - 你有没有指令停止超时后等待输入经过。你需要找到相当于['select']的haskell(http://linux.die.net/man/2/select)。 – rampion

+0

'recvFrom'是恕我直言,不阻止 –

回答

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。它的实现也比这个更可能是正确的。

+0

感谢您的超时事情。将研究这一点。 Conc MVar预计如果在更大的规模上使用它会很慢。我尝试制作速度非常快,并且代码量最小的代码。我也会尝试MVar。 –

+0

任何想法为什么'只是一个< - 超时50(recvFrom s 4711)'会在运行时返回一个模式匹配错误达到超时 –

+0

@JFritsch:因为如果它超时,结果是'Nothing'当然不会' t匹配'只是'。 – hammar

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' 
+0

冻结。完全一样的结果。我从来没有预料到这个编译,因为我会期待cond1 || cond2必须是相同的类型。 –

+0

@JFritsch:在这种情况下,它听起来像'recvFrom'阻塞。另外,'B.unpack a =='ack“'和'now'> = duetime''都有'Bool'类型。 – hammar