Software transactional memory

A transaction in this context occurs when a piece of code executes a series of reads and writes to shared memory.

These reads and writes logically occur at a single instant in time; intermediate states are not visible to other (successful) transactions.

[2] In 1995, Nir Shavit and Dan Touitou extended this idea to software-only transactional memory (STM).

If a transaction cannot be committed due to conflicting changes, it is typically aborted and re-executed from the beginning until it succeeds.

Deadlock and livelock are either prevented entirely or handled by an external transaction manager; the programmer need hardly worry about it.

Such limits are typically overcome in practice by creating buffers that queue up the irreversible operations and perform them after the transaction succeeds.

In 2005, Tim Harris, Simon Marlow, Simon Peyton Jones, and Maurice Herlihy described an STM system built on Concurrent Haskell that enables arbitrary atomic operations to be composed into larger atomic operations, a useful concept impossible with lock-based programming.

To quote the authors: Perhaps the most fundamental objection [...] is that lock-based programs do not compose: correct fragments may fail when combined.

The only sticking point is that it is unclear to the caller, who is unaware of the implementation details of the component methods, when it should attempt to re-execute the transaction if it fails.

[clarification needed] This facility, comparable to features such as the Portable Operating System Interface (POSIX) networking select() call, allows the caller to wait on any one of a number of events simultaneously.

This loose coupling between producers and consumers enhances modularity compared to explicit signaling between threads.

For example: This ability to retry dynamically late in the transaction simplifies the programming model and opens up new possibilities.

A commit-time scheme named "Transactional Locking II" implemented by Dice, Shalev, and Shavit uses a global version clock.

Then, on every read or write, the version of the particular memory location is compared to the read-version; and, if it is greater, the transaction is aborted.