liveBook · Manning

Software transactional memory

As explained in Functional Design and Architecture: Examples in Haskell

Software transactional memory is a concurrency technique that manages shared state through transactional memory operations rather than explicit locking, with composable transactions supporting coordinated composition.

Software transactional memory (STM) manages concurrent mutable state by allowing changes only inside isolated transactions. Separate threads can safely update independent parts of a domain model; when they collide, STM resolves access predictably through waiting, retrying, or rollback rather than hand-built locking protocols. section 9.2 section 7.2.4

The practical design split is simple: build a concurrent domain model from transactional variables and structures, then write transaction functions that modify it. Run those functions atomically in the threaded environment. This separates state representation from behavior while retaining thread-safety. section 9.2.1

STM is most useful when coordination spans more than one shared value:

  • Use TVars as fundamental transactional variables; build structures such as FIFO queues from them when the domain needs them. section 9.2.1
  • Compose small STM actions into one larger transaction, so related updates are evaluated as a single coordinated operation. section 9.2.1
  • Use retry to block a transaction until observed state changes make progress possible, rather than repeatedly polling a resource. section 9.2.2
  • Prefer STM when an MVar-based model becomes large or awkward; manually paired acquire-and-release operations are easy to get wrong. section 8.3 section 9.2.2

Bounded process counter

A runtime can keep its current process count in a TVar. The increment transaction reads the count, calls retry at the configured limit, and otherwise writes the incremented value. A decrement transaction simply updates the TVar. Executing each with atomically yields sequential-looking resource control without manual polling or race-prone coordination. section 9.2.2

Figure 9.9 Data model and behavior model in STM

This diagram clarifies the central STM separation: transactional structures form the data model, while transactions form the behavior model executed against it. section 9.2.1

STM can also sit behind an application interface. A reporting channel, for example, can change from an IORef to a TVar, with its update expressed as STM and lifted into business logic through an atomic interpreter. Direct raw mutable references shared across threads are unsafe; deeper state abstraction may be needed when variables must be inspected, limited, persisted, or restored. section 9.2.3

How Functional Design and Architecture: Examples in Haskell covers it

How deep it goes
Explains TVars, transactions, atomic execution, retry, composition, and framework integration, while deferring deeper STM and thread subtleties.
Examples
Uses a forest-like TVar model, transactional queue, dining philosophers, bounded process counter, and meteor reporting channel.
What it assumes
Assumes familiarity with mutable references and threading while contrasting IORefs, MVars, and TVars for concurrent design.
What you can do after
Apply it via Haskell STM primitives to build transactional state, compose updates, and block safely with retry.
How it connects
Connects STM with TVars, TQueues, MVars, IORefs, free monads, threads, and reactive programming.

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.