| Copyright | (c) The University of Glasgow 2001 |
|---|---|
| License | BSD-style (see the file libraries/base/LICENSE) |
| Maintainer | libraries@haskell.org |
| Stability | experimental |
| Portability | non-portable (concurrency) |
| Safe Haskell | Trustworthy |
| Language | Haskell2010 |
Control.Concurrent.MVar
Contents
Description
An is mutable location that is either empty or contains a value of typeMVar tt. It has two fundamental operations:putMVar which fills anMVar if it is empty and blocks otherwise, andtakeMVar which empties anMVar if it is full and blocks otherwise. They can be used in multiple different ways:
takeMVar andputMVar as receive and send, andMVar (), withtakeMVar andputMVar as wait and signal.They were introduced in the paper"Concurrent Haskell" by Simon Peyton Jones, Andrew Gordon and Sigbjorn Finne, though some details of their implementation have since then changed (in particular, a put on a fullMVar used to error, but now merely blocks.)
MVars offer more flexibility thanIORefs, but less flexibility thanSTM. They are appropriate for building synchronization primitives and performing simple interthread communication; however they are very simple and susceptible to race conditions, deadlocks or uncaught exceptions. Do not use them if you need perform larger atomic operations such as reading from multiple variables: useSTM instead.
In particular, the "bigger" functions in this module (swapMVar,withMVar,modifyMVar_ andmodifyMVar) are simply the composition of atakeMVar followed by aputMVar with exception safety. These only have atomicity guarantees if all other threads perform atakeMVar before aputMVar as well; otherwise, they may block.
No thread can be blocked indefinitely on anMVar unless another thread holds thatMVar indefinitely. One usual implementation of this fairness guarantee is that threads blocked on anMVar are served in a first-in-first-out fashion, but this is not guaranteed in the semantics.
Like many other Haskell data structures,MVars are lazy. This means that if you place an expensive unevaluated thunk inside anMVar, it will be evaluated by the thread that consumes it, not the thread that produced it. Be sure toevaluate values to be placed in anMVar to the appropriate normal form, or utilize a strict MVar provided by the strict-concurrency package.
MVar operations are always observed to take place in the order they are written in the program, regardless of the memory model of the underlying machine. This is in contrast toIORef operations which may appear out-of-order to another thread in some cases.
Consider the following concurrent data structure, a skip channel. This is a channel for an intermittent source of high bandwidth information (for example, mouse movement events.) Writing to the channel never blocks, and reading from the channel only returns the most recent value, or blocks if there are no new values. Multiple readers are supported with adupSkipChan operation.
A skip channel is a pair ofMVars. The firstMVar contains the current value, and a list of semaphores that need to be notified when it changes. The secondMVar is a semaphore for this particular reader: it is full if there is a value in the channel that this reader has not read yet, and empty otherwise.
data SkipChan a = SkipChan (MVar (a, [MVar ()])) (MVar ()) newSkipChan :: IO (SkipChan a) newSkipChan = do sem <- newEmptyMVar main <- newMVar (undefined, [sem]) return (SkipChan main sem) putSkipChan :: SkipChan a -> a -> IO () putSkipChan (SkipChan main _) v = do (_, sems) <- takeMVar main putMVar main (v, []) mapM_ (sem -> putMVar sem ()) sems getSkipChan :: SkipChan a -> IO a getSkipChan (SkipChan main sem) = do takeMVar sem (v, sems) <- takeMVar main putMVar main (v, sem:sems) return v dupSkipChan :: SkipChan a -> IO (SkipChan a) dupSkipChan (SkipChan main _) = do sem <- newEmptyMVar (v, sems) <- takeMVar main putMVar main (v, sem:sems) return (SkipChan main sem)
This example was adapted from the original Concurrent Haskell paper. For more examples ofMVars being used to build higher-level synchronization primitives, seeChan andQSem.
MVarsAnMVar (pronounced "em-var") is a synchronising variable, usedfor communication between concurrent threads. It can be thought ofas a box, which may be empty or full.
takeMVar ::MVar a ->IO aSource#
Return the contents of theMVar. If theMVar is currently empty,takeMVar will wait until it is full. After atakeMVar, theMVar is left empty.
There are two further important properties oftakeMVar:
takeMVar is single-wakeup. That is, if there are multiple threads blocked intakeMVar, and theMVar becomes full, only one thread will be woken up. The runtime guarantees that the woken thread completes itstakeMVar operation.MVar, they are woken up in FIFO order. This is useful for providing fairness properties of abstractions built usingMVars.putMVar ::MVar a -> a ->IO ()Source#
Put a value into anMVar. If theMVar is currently full,putMVar will wait until it becomes empty.
There are two further important properties ofputMVar:
putMVar is single-wakeup. That is, if there are multiple threads blocked inputMVar, and theMVar becomes empty, only one thread will be woken up. The runtime guarantees that the woken thread completes itsputMVar operation.MVar, they are woken up in FIFO order. This is useful for providing fairness properties of abstractions built usingMVars.readMVar ::MVar a ->IO aSource#
Atomically read the contents of anMVar. If theMVar is currently empty,readMVar will wait until it is full.readMVar is guaranteed to receive the nextputMVar.
readMVar is multiple-wakeup, so when multiple readers are blocked on anMVar, all of them are woken up at the same time.
Compatibility note: Prior to base 4.7,readMVar was a combination oftakeMVar andputMVar. This mean that in the presence of other threads attempting toputMVar,readMVar could block. Furthermore,readMVar would not receive the nextputMVar if there was already a pending thread blocked ontakeMVar. The old behavior can be recovered by implementing 'readMVar as follows:
readMVar :: MVar a -> IO a readMVar m = mask_ $ do a <- takeMVar m putMVar m a return a
tryTakeMVar ::MVar a ->IO (Maybe a)Source#
A non-blocking version oftakeMVar. ThetryTakeMVar function returns immediately, withNothing if theMVar was empty, or if theJust aMVar was full with contentsa. AftertryTakeMVar, theMVar is left empty.
tryPutMVar ::MVar a -> a ->IOBoolSource#
A non-blocking version ofputMVar. ThetryPutMVar function attempts to put the valuea into theMVar, returningTrue if it was successful, orFalse otherwise.
isEmptyMVar ::MVar a ->IOBoolSource#
Check whether a givenMVar is empty.
Notice that the boolean value returned is just a snapshot of the state of the MVar. By the time you get to react on its result, the MVar may have been filled (or emptied) - so be extremely careful when using this operation. UsetryTakeMVar instead if possible.
withMVar ::MVar a -> (a ->IO b) ->IO bSource#
withMVar is an exception-safe wrapper for operating on the contents of anMVar. This operation is exception-safe: it will replace the original contents of theMVar if an exception is raised (seeControl.Exception). However, it is only atomic if there are no other producers for thisMVar.
withMVarMasked ::MVar a -> (a ->IO b) ->IO bSource#
LikewithMVar, but theIO action in the second argument is executed with asynchronous exceptions masked.
Since: 4.7.0.0
modifyMVar_ ::MVar a -> (a ->IO a) ->IO ()Source#
An exception-safe wrapper for modifying the contents of anMVar. LikewithMVar,modifyMVar will replace the original contents of theMVar if an exception is raised during the operation. This function is only atomic if there are no other producers for thisMVar.
modifyMVar ::MVar a -> (a ->IO (a, b)) ->IO bSource#
A slight variation onmodifyMVar_ that allows a value to be returned (b) in addition to the modified value of theMVar.
modifyMVarMasked_ ::MVar a -> (a ->IO a) ->IO ()Source#
LikemodifyMVar_, but theIO action in the second argument is executed with asynchronous exceptions masked.
Since: 4.6.0.0
modifyMVarMasked ::MVar a -> (a ->IO (a, b)) ->IO bSource#
LikemodifyMVar, but theIO action in the second argument is executed with asynchronous exceptions masked.
Since: 4.6.0.0
addMVarFinalizer ::MVar a ->IO () ->IO ()Source#
Deprecated: usemkWeakMVar instead
Produced byHaddock version 2.20.0