我想實作一個簡單的計時器,我可以
- 隨時退出并得到結果
- 運行任意次數。
我提出了timer1實施方案。它滿足(2)并且幾乎滿足(1),因為它必須等到threadDelay完成。任何指標將不勝感激。
附:catch我嘗試過的具有例外處理的另一個實作立即退出,但無法通過 SIGINT 退出兩次,否則程式將終止。
timer1 :: MVar () -> Int -> IO Int
timer1 v sec = do
putStrLn (show sec)
threadDelay 1000000
tryTakeMVar v >>= \case
Just _ -> return sec
Nothing -> exitCond
where
exitCond = if sec > 0 then timer1 v (sec - 1) else return 0
main :: IO ()
main = do
v <- newEmptyMVar
installHandler sigINT (CatchOnce $ putMVar v ()) Nothing
res <- timer1 v 5
putStrLn $ "timer1: " show res
v <- newEmptyMVar
installHandler sigINT (CatchOnce $ putMVar v ()) Nothing
res <- timer1 v 5
putStrLn $ "timer1: " show res
uj5u.com熱心網友回復:
我建議生成一個等待適當時間然后填充 MVar 的執行緒:
import Data.Time.Clock
timer1 :: MVar () -> Int -> IO Int
timer1 m sec = do
before <- getCurrentTime
forkIO (threadDelay (sec*1000000) >> putMVar m ())
takeMVar m
after <- getCurrentTime
return (sec - floor (diffUTCTime after before))
無論分叉的threadDelay或信號處理程式,火災首先會醒過來timer1的takeMVar。
您main可以保持不變。
uj5u.com熱心網友回復:
這是我快速整理的內容:
{-# LANGUAGE LambdaCase #-}
import Control.Concurrent
import System.Posix
import Data.IORef
timer1 :: MVar () -> IORef Int -> Int -> IO ()
timer1 v t sec = do
writeIORef t sec
putStrLn (show sec)
threadDelay 1000000
if sec > 0
then timer1 v t (sec - 1)
else putMVar v ()
main :: IO ()
main = do
v <- newEmptyMVar
t <- newIORef 5
installHandler sigINT (CatchOnce $ putMVar v ()) Nothing
tid <- forkIO $ timer1 v t 5
takeMVar v -- wait for timer or user interrupt
killThread tid -- stop the timer
res <- readIORef t -- read the current time
putStrLn $ "timer1: " show res
v <- newEmptyMVar
t <- newIORef 5
installHandler sigINT (CatchOnce $ putMVar v ()) Nothing
tid <- forkIO $ timer1 v t 5
takeMVar v
killThread tid
res <- readIORef t
putStrLn $ "timer1: " show res
主要思想是將MVar兩者用于信號和定時器結束。然后你可以在一個單獨的執行緒中運行計時器并等待MVar主執行緒中的 被填充。這意味著您確實需要以其他方式跟蹤當前時間,IORef為此我選擇使用 an 。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/316858.html
標籤:哈斯克尔
上一篇:Haskell代碼如何在使用串列推導式時利用括號來分隔或整理資訊?
下一篇:如何檢查元音?
