A condition variable like "release and wait" operation for `MVar`s
Consider a simple barrier implementation using readMVar
to notify waiting threads (to avoid having a list of MVar
s):
import Control.Concurrent.MVar
data Barrier = Barrier !Int !(MVar Int) !(MVar ())
new :: Int -> IO Barrier
new n
| n <= 0 = error "the number must be positive"
| otherwise = do
count <- newMVar n
waker <- newEmptyMVar
pure $ Barrier n count waker
wait :: Barrier -> IO ()
wait (Barrier n count waker) = do
c <- takeMVar count
if c == 1 then do
-- all other threads are already waiting
putMVar count n
putMVar waker ()
takeMVar waker
else do
putMVar count $! c - 1
-- another thread might notify here
readMVar waker
This has a problem: between the putMVar count ...
and the readMVar waker
, another thread might call wait
and notify all sleeping threads. This would cause the readMVar
to block forever. It would be ncie if there was a "release and wait" primitive to atomically do the putMVar count ...
and then readMVar waker
(similar to a condition variable). Or is it already possible to do this somehow?