Copyright | (c) Joseph Adams 2012 |
---|---|
License | BSD3 |
Maintainer | joeyadams3.14159@gmail.com |
Portability | Requires GHC 7+ |
Safe Haskell | None |
Language | Haskell98 |
One-shot timer whose duration can be updated. Think of it as an enhanced
version of registerDelay
.
This uses GHC.Event when available (GHC 7.2+, -threaded
, non-Windows OS).
Otherwise, it falls back to forked threads and threadDelay
.
Managing delays
newDelay :: Int -> IO Delay Source
Create a new Delay
that will ring in the given number of microseconds.
updateDelay :: Delay -> Int -> IO () Source
Set an existing Delay
to ring in the given number of microseconds
(from the time updateDelay
is called), rather than when it was going to
ring. If the Delay
has already rung, do nothing.
cancelDelay :: Delay -> IO () Source
Set a Delay
so it will never ring, even if updateDelay
is used later.
If the Delay
has already rung, do nothing.
Waiting for expiration
tryWaitDelay :: Delay -> STM Bool Source
tryWaitDelayIO :: Delay -> IO Bool Source
Faster version of
. See atomically
. tryWaitDelay
readTVarIO
.
Since 0.1.1
Example
Suppose we are managing a network connection, and want to time it out if no
messages are received in over five minutes. We'll create a Delay
, and an
action to "bump" it:
let timeoutInterval = 5 * 60 * 1000000 ::Int
delay <-newDelay
timeoutInterval let bump =updateDelay
delay timeoutInterval
This way, the Delay
will ring if it is not bumped for longer than
five minutes.
Now we fork the receiver thread:
dead <-newEmptyTMVarIO
_ <-forkIO
$ (forever
$ do msg <- recvMessage bump handleMessage msg ) `finally`atomically
(putTMVar
dead ())
Finally, we wait for the delay to ring, or for the receiver thread to fail due to an exception:
atomically
$waitDelay
delay `orElse`readTMVar
dead
Warning:
- If handleMessage blocks, the
Delay
may ring due tohandleMessage
taking too long, rather than justrecvMessage
taking too long. - The loop will continue to run until you do something to stop it.
It might be simpler to use System.Timeout instead:
m <-timeout
timeoutInterval recvMessage case m of Nothing ->fail
"timed out" Just msg -> handleMessage msg
However, using a Delay
has the following advantages:
- If
recvMessage
makes a blocking FFI call (e.g. network I/O on Windows),timeout
won't work, since it uses an asynchronous exception, and FFI calls can't be interrupted with async exceptions. TheDelay
approach lets you handle the timeout in another thread, while the FFI call is still blocked. updateDelay
is more efficient thantimeout
when GHC.Event is available.