Skip to content

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?

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information