6 Basics [basic]

6.10 Program execution [basic.exec]

6.10.2 Multi-threaded executions and data races [intro.multithread]


6.10.2.1 General [intro.multithread.general]

6.10.2.2 Data races [intro.races]

6.10.2.3 Forward progress [intro.progress]


6.10.2.1 General [intro.multithread.general]

A thread of execution (also known as a thread) is a single flow of control within a program, including the initial invocation of a specific top-level function, and recursively including every function invocation subsequently executed by the thread.
[Note 1: 
When one thread creates another, the initial call to the top-level function of the new thread is executed by the new thread, not by the creating thread.
— end note]
Every thread in a program can potentially use every object and function in a program.³¹
Under a hosted implementation, a C++ program can have more than one thread running concurrently.
The execution of each thread proceeds as defined by the remainder of this document.
The execution of the entire program consists of an execution of all of its threads.
[Note 2: 
Usually the execution can be viewed as an interleaving of all its threads.
However, some kinds of atomic operations, for example, allow executions inconsistent with a simple interleaving, as described below.
— end note]
Under a freestanding implementation, it is implementation-defined whether a program can have more than one thread of execution.
For a signal handler that is not executed as a result of a call to the std​::​raise function, it is unspecified which thread of execution contains the signal handler invocation.
31)31)
An object with automatic or thread storage duration ([basic.stc]) is associated with one specific thread, and can be accessed by a different thread only indirectly through a pointer or reference ([basic.compound]).

6.10.2.2 Data races [intro.races]

The value of an object visible to a thread T at a particular point is the initial value of the object, a value assigned to the object by T, or a value assigned to the object by another thread, according to the rules below.
[Note 1: 
In some cases, there might instead be undefined behavior.
Much of this subclause is motivated by the desire to support atomic operations with explicit and detailed visibility constraints.
However, it also implicitly supports a simpler view for more restricted programs.
— end note]
Two expression evaluations conflict if one of them and the other one
  • reads or modifies the same memory location or
  • starts or ends the lifetime of an object occupying storage that overlaps with the memory location.
[Note 2: 
A modification can still conflict even if it does not alter the value of any bits.
— end note]
The library defines a number of atomic operations ([atomics]) and operations on mutexes (Clause [thread]) that are specially identified as synchronization operations.
These operations play a special role in making assignments in one thread visible to another.
A synchronization operation on one or more memory locations is either an acquire operation, a release operation, or both an acquire and release operation.
A synchronization operation without an associated memory location is a fence and can be either an acquire fence, a release fence, or both an acquire and release fence.
In addition, there are relaxed atomic operations, which are not synchronization operations, and atomic read-modify-write operations, which have special characteristics.
[Note 3: 
For example, a call that acquires a mutex will perform an acquire operation on the locations comprising the mutex.
Correspondingly, a call that releases the same mutex will perform a release operation on those same locations.
Informally, performing a release operation on A forces prior side effects on other memory locations to become visible to other threads that later perform a consume or an acquire operation on A.
“Relaxed” atomic operations are not synchronization operations even though, like synchronization operations, they cannot contribute to data races.
— end note]
All modifications to a particular atomic object M occur in some particular total order, called the modification order of M.
[Note 4: 
There is a separate order for each atomic object.
There is no requirement that these can be combined into a single total order for all objects.
In general this will be impossible since different threads can observe modifications to different objects in inconsistent orders.
— end note]
A release sequence headed by a release operation A on an atomic object M is a maximal contiguous sub-sequence of side effects in the modification order of M, where the first operation is A, and every subsequent operation is an atomic read-modify-write operation.
Certain library calls synchronize with other library calls performed by another thread.
For example, an atomic store-release synchronizes with a load-acquire that takes its value from the store ([atomics.order]).
[Note