Thread safety keeps shared state usable when several threads access it at once. Plain mutable references make each read and write possible, but leave coordination to the developer; competing operations can become nondeterministic or race. Atomic thread-safe variables improve the primitive operation, yet application-level correctness still depends on how reads, writes, and resource use are composed. section 7.2.4 section 9.1.2
A reporting channel that loses events
A meteor-reporting channel stored as an IORef list is updated by reading the list and writing back a new one. An astronomer thread reports meteors while a tracking-center thread reads the list and clears it. Those separate steps can interleave: reports may be lost, processed twice, or outpace consumption, with memory use growing as a result. section 9.1.2 section 9.1.2
Choose synchronization at the shape of the state. An MVar provides atomic reading and writing, but does not by itself eliminate race conditions, deadlocks, or nondeterminism across a larger protocol. Software transactional memory (STM) instead performs mutations in isolated transactions; competing transactions can be delayed or retried, and transactional operations can be combined. section 7.2.4 section 7.2.4
Figure 9.3 Race condition in accessing a shared resource and double-usage error
Trace the interleaving between reporting and clearing the shared channel to see why individually simple IORef operations do not make the workflow safe. section 9.1.2
Thread safety also requires controlling which concurrent actions business logic may express. A layered design can expose operations for shared state, delays, and random values while reserving process creation for a top-level application layer. Restricting child processes from forking further threads makes unbounded thread creation impossible to represent and keeps resource-pool limits enforceable. section 9.1.3 section 9.1.3
Granularity changes the concurrency trade-off. A simulator runtime can use an outer MVar map whose values are themselves MVars, allowing independent keys to be updated without replacing the entire map. A coarse-grained MVar around a whole map instead requires repeated whole-map updates and may be less efficient when the same key changes often. section 8.2.2 section 8.2.2







