2012-03-05 125 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