Software transactional memory (STM) is a non-blocking software-based synchronization mechanism that allows programmers to execute sequences of operations on shared data structures as atomic transactions, ensuring isolation, atomicity, and consistency without relying on traditional locks or hardware support.[1] Transactions in STM are finite sequences of read and write operations that speculatively execute in isolation, logging changes privately until a commit attempt, at which point conflicts with concurrent transactions trigger aborts and retries to maintain linearizability.[1] This approach draws inspiration from database transactions but applies them to in-memory data, using primitive operations like compare-and-swap to manage contention.[2]The concept of transactional memory originated with the 1993 proposal by Maurice Herlihy and J. Eliot B. Moss for hardware transactional memory (HTM), which aimed to provide architectural support for lock-free data structures by extending cache coherence protocols to handle multi-word atomic operations.[3] Building on this foundation, STM was introduced in 1995 by Nir Shavit and Dan Touitou as a portable, software-only alternative that leverages existing hardware primitives like load-linked/store-conditional to implement dynamic or static transactions without specialized processors.[1] Early motivations included overcoming the limitations of lock-based synchronization, such as deadlocks, priority inversion, and poor scalability in multiprocessor environments, while simplifying the development of concurrent programs.[3]STM systems typically employ optimistic concurrency control, where transactions proceed assuming no conflicts, buffering writes in thread-local logs and validating them against global state during commit; upon detection of a read-write or write-write conflict, the transaction aborts and restarts.[2] Key design variations include object-based versus word-based implementations, eager versus lazy conflict detection, and support for dynamic transactions that access unbounded memory sets.[2] Pioneering systems like DSTM (Dynamic STM) by Herlihy et al. introduced obstruction-free progress guarantees and features such as invisible reads to reduce contention, while others like FSTM emphasized lock-free helping mechanisms for better scalability.[2]Among STM's primary advantages are its composability—allowing fine-grained transactions to nest or compose without explicit lock management—and resilience to programming errors that plague locking, such as forgotten unlocks leading to deadlocks.[4] However, challenges persist, including runtime overhead from logging, validation, and retries, which can degrade performance under high contention compared to fine-grained locking.[2] Despite these, STM has influenced modern languages like Haskell and Clojure, and hybrid approaches combining STM with hardware TM continue to evolve for high-performance computing.[4]
Overview
Definition and Basic Concepts
Software transactional memory (STM) is a software-based concurrency control mechanism that allows multiple threads to execute blocks of code atomically and in isolation by treating groups of read and write operations on shared memory as transactions, thereby simplifying parallel programming without the need for explicit locks.[5][2] In this model, a transaction is a finite sequence of memory operations that must appear to execute indivisibly from the perspective of other transactions, ensuring that either all operations succeed (commit) or none do (abort), with changes rolled back in the latter case.[5] The commit phase atomically installs the transaction's updates into shared memory upon successful validation, while an abort discards all modifications and restarts the transaction if necessary.[2]The basic workflow of STM relies on optimistic concurrency control, where transactions proceed assuming no conflicts, buffering writes locally or using versioning to track changes.[5] During execution, reads and writes are performed on shared data, often mediated by ownership records or metadata to detect concurrent access; conflicts arise when another transaction has modified a location read by the current one or vice versa.[2] Conflict detection typically occurs lazily at commit time through validation (e.g., checking version numbers) or eagerly during reads/writes, triggering an abort and retry mechanism to resolve inconsistencies without blocking other threads.[5] This process provides atomicity and isolation, akin to database transactions, though implementations vary in their use of fine-grained locking, non-blocking primitives like compare-and-swap, or timestamping for conflict management.[2]A simple pseudocode example illustrates a transactional read-modify-write operation, such as incrementing a shared counter:
atomic {
val = read(counter); // Read current value
new_val = val + 1; // Local computation
write(counter, new_val); // Buffered write
} // Implicit commit or abort
In this construct, the atomic block delimits the transaction; upon commit, the increment is applied atomically if no conflicts are detected, otherwise the transaction aborts and retries from the read.[5]
History and Evolution
The concept of transactional memory drew early inspiration from database transaction models developed in the 1980s, which ensured atomicity, consistency, isolation, and durability (ACID properties) for concurrent data access.[6] This analogy influenced proposals for hardware transactional memory (HTM) in the 1990s, aiming to simplify lock-free synchronization in multiprocessor systems. A seminal contribution was the 1993 paper by Maurice Herlihy and J. Eliot B. Moss, which introduced transactional memory as an architectural mechanism to enable optimistic concurrency control, treating groups of memory operations as atomic units buffered in a transaction buffer and committed or aborted as a whole.[6]The shift to software-only transactional memory (STM) occurred in 1995, when Nir Shavit and Dan Touitou proposed a non-blocking implementation that simulated hardware transactions using fine-grained locking and versioning on shared data structures.[7] This work established STM as a portable alternative to hardware support, focusing on dynamic transactions where accessed objects are not predetermined. Building on this foundation, the early 2000s saw practical implementations emerge; notably, Tim Harris and Keir Fraser developed a word-based STM library for Java in 2003, incorporating optimistic concurrency with dynamic ownership tracking to manage conflicts efficiently.