The Two Flavors of Transactional Memory
C++ supports transactional memory in two flavors: synchronized blocks and atomic blocks.
Synchronized & Atomic Blocks
Up to now, I only wrote about transactions. Now, I will write about synchronized blocks and atomic blocks. Both can be encapsulated in each other; specifically, synchronized blocks are not atomic blocks because they can execute transaction-unsafe. An example would be code like the output to the console which can not be undone. For this reason, synchronized blocks are often called relaxed blocks.
Synchronized blocks behave like they are protected by a global lock, i.e. This means that all synchronized blocks follow a total order. In particular: all changes to a synchronized block are available in the next synchronized block. There is a synchronizes-with relation between the synchronized blocks because of the commit of the transaction synchronizes-with the next start of a transaction. Synchronized blocks cannot cause a deadlock because they create a total order. While a classical lock protects a memory area, a global lock of a synchronized block protects the total program. This is the reason the following program is well-defined: