Transactional memory is intended to make programming with threads simpler, in particular synchronizing access to data shared between several threads using transactions. As with databases, a transaction is a unit of work that either completes in its entirety or has no effect at all (i.e., transactions execute atomically). Further, transactions are isolated from each other such that each transaction sees a consistent view of memory.
Two operations conflict if one of them modifies a memory location and the other one
accesses or modifies the same memory location. The execution of a program contains a data race if it
contains two conflicting operations in different threads, at least one of which is not an atomic operation,
and neither happens before the other. Any such data race results in undefined behavior. A program is race free if none of its executions contain a data race. In a race-free program each read from a memory location
sees the value written by the last write ordered before it by the “happens-before” relationship.
Outermost transactions (that is, transactions that are not dynamically nested within other
transactions) appear to execute sequentially in some total global order that contributes to the
“synchronizes with” relationship. Conceptually, every outermost transaction is associated with
StartTransaction and EndTransaction operations, which mark the beginning and end of the
transaction.2 A StartTransaction operation is sequenced before all other operations of its
transaction. All operations of a transaction are sequenced before its EndTransaction operation.
A shared memory access can form a data race even if it is performed in a transaction
statement. In the following example, a write by thread T2 forms a data race with both read and
write to x by Thread T1 because it is not ordered with the operations of Thread T1 by the
“happens-before” relationship. To avoid a data race in this example, a programmer should
enclose the write to x in Thread T2 in a transaction statement.
Thread T1
__transaction {
t = x;
x = t+1;
}
Thread T2
x = 1;
Atomic transactions:
A transaction statement without an attribute or annotated with the atomic attribute defines an
atomic transaction. We call such a statement an atomic transaction statement:
__transaction compound-statement
__transaction [[ atomic ]]compound-statement
Safety attributes on functions and function pointers:
To ensure that atomic transactions can be executed atomically, certain statements must not be
executed within atomic transactions; we call such statements unsafe.
In order to specify whether a function is safe, the function declaration may specify transaction_safe or transaction_unsafe attribute.
Memory model;
The memory model rules for transactions (Section 2.1) are sufficient to guarantee that in race
free programs, atomic transactions appear to execute as single indivisible operations. Atomic
transactions cannot contain other forms of synchronization (such as operations on locks or C++0x
atomic operations).
In the following example, both a and b will be read and the difference will be written to c, all atomically and isolated from other transactions:
__transaction_atomic { c = a - b; }
Therefore, another thread can use the following code to concurrently update b without ever causing c to hold a negative value (and without having to use other synchronization constructs such as locks or C++11 atomics): __transaction_atomic { if (a > b) b++; }
refer: C++-transactional-constructs-1.0.pdf