liveBook · Manning

MVar

As explained in Functional Design and Architecture: Examples in Haskell

An MVar is a Haskell mutable synchronization variable that stores either no value or one value and supports coordinated access between concurrent computations.

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

How Functional Design and Architecture: Examples in Haskell covers it

How deep it goes
Defines empty/full blocking semantics and builds a two-MVar service, while deferring broader MVar problems.
Examples
Implements a Pipe, worker, FizzBuzz processor, generator, and a synchronized thread counter.
What it assumes
Assumes familiarity with IO and threads while introducing MVar creation, reading, writing, and blocking from first principles.
What you can do after
Apply it to build a typed request–response service and recognize when STM better fits complex state.
How it connects
Contrasts IORef with STM, TVar, transactions, deadlocks, and the actor model.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Design and Architecture: Examples in Haskell. The section links point to the parts of the book it draws on.