An MVar is a thread-safe mutable variable in the IO layer. It holds either no value or one value, making it useful when concurrent computations need to hand work or state to one another without simultaneous access. Unlike an IORef, its reads and writes are atomic; it is still mutable state, so race conditions, deadlocks, and nondeterminism remain design concerns. section 7.2.4 section 8.1.3
The two states drive its coordination behavior. A thread taking an empty MVar blocks until another thread puts a value in it. A thread putting into a full MVar blocks until it becomes empty. Threads wait their turn, so the shared value cannot be observed or changed simultaneously. section 8.1.3
Figure 8.5 The MVar Request–Response pattern flow
The request–response flow shows how two MVars form a channel: one carries work to a responder, and the other returns its result to the requester. section 8.1.3
A two-MVar request–response service
A Pipe pairs a request MVar with a response MVar. sendRequest puts an input into the request slot, then takes the response. A worker repeatedly takes requests, applies a function, and puts results back. The FizzBuzz service runs the worker and generator in separate threads, turning each input into a returned string. section 8.1.3
Keep the ownership protocol explicit:
- Pair every takeMVar with a later putMVar. A branch that takes a value but never replaces it leaves other threads blocked indefinitely. section 8.1.3
- Account for thread failure. If a thread takes an MVar and dies, other threads can remain blocked and the program can terminate. section 9.2.2
- Prefer a protocol such as request–response for a small interaction, but reconsider MVar-based designs as concurrent state becomes large or sophisticated. section 8.3
- Use STM and TVars when coordinated state needs transactions, retries, or composition across operations; transactions isolate competing mutations and can reduce deadlock risk. section 7.2.4 section 9.2.2
MVars can safely synchronize a shared counter or implement a separate-thread service, but correctness depends on carefully pairing acquisition and release. Multiple MVars amplify that burden. STM replaces manual coordination with transactional variables and retry-based blocking, allowing sequential-looking code to handle contention predictably. section 8.3 section 9.2.2
