
Suppose that a program using the Control.Concurrent.STM module had a producer/consumer setup - one thread writing to a channel, the other thread reading from the channel. It seems natural to want a function that the producer can call that will block until the consumer has finished consuming everything currently in the channel. The way I first tried implementing this was: -- types simplified for this example flush :: TChan () -> STM () flush chan = do e <- isEmptyTChan if not e then retry else return () Used in isolation, i.e. atomically $ writeTChan chan () atomically $ flush chan it works fine. However, when composed (atomically $ writeTChan chan () >> flush chan), it causes a race condition, usually resulting in deadlock, as the "retry" in flush replays the call to writeTChan as well. This situation begs for a way to limit the scope of "retry", in which case flush would be: flush chan = limitRetry $ do e <- isEmptyTChan if not e then retry else return () Abe