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 MVars):
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?