Init
This commit is contained in:
472
cppdraft/intro/races.md
Normal file
472
cppdraft/intro/races.md
Normal file
@@ -0,0 +1,472 @@
|
||||
[intro.races]
|
||||
|
||||
# 6 Basics [[basic]](./#basic)
|
||||
|
||||
## 6.10 Program execution [[basic.exec]](basic.exec#intro.races)
|
||||
|
||||
### 6.10.2 Multi-threaded executions and data races [[intro.multithread]](intro.multithread#intro.races)
|
||||
|
||||
#### 6.10.2.2 Data races [intro.races]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6607)
|
||||
|
||||
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[.](#1.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
In some cases, there might instead be undefined behavior[.](#1.sentence-2)
|
||||
|
||||
Much of this
|
||||
subclause is motivated by the desire to support atomic operations with explicit
|
||||
and detailed visibility constraints[.](#1.sentence-3)
|
||||
|
||||
However, it also implicitly supports a
|
||||
simpler view for more restricted programs[.](#1.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6618)
|
||||
|
||||
Two expression evaluations [*conflict*](#def:conflict "6.10.2.2 Data races [intro.races]") if one of them
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
modifies ([[defns.access]](defns.access "3.1 access")) a memory location ([[intro.memory]](intro.memory "6.8.1 Memory model")) or
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
starts or ends the lifetime of an object in a memory location
|
||||
|
||||
and the other one
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
reads or modifies the same memory location or
|
||||
|
||||
- [(2.4)](#2.4)
|
||||
|
||||
starts or ends the lifetime of an object occupying storage that
|
||||
overlaps with the memory location[.](#2.sentence-1)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
A modification can still conflict
|
||||
even if it does not alter the value of any bits[.](#2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6639)
|
||||
|
||||
The library defines a number of atomic operations ([[atomics]](atomics "32.5 Atomic operations")) and
|
||||
operations on mutexes ([[thread]](thread "32 Concurrency support library")) that are specially identified as
|
||||
synchronization operations[.](#3.sentence-1)
|
||||
|
||||
These operations play a special role in making
|
||||
assignments in one thread visible to another[.](#3.sentence-2)
|
||||
|
||||
A synchronization operation on one
|
||||
or more memory locations is either an acquire operation, a
|
||||
release operation, or both an acquire and release operation[.](#3.sentence-3)
|
||||
|
||||
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[.](#3.sentence-4)
|
||||
|
||||
In
|
||||
addition, there are relaxed atomic operations, which are not synchronization
|
||||
operations, and atomic read-modify-write operations, which have special
|
||||
characteristics[.](#3.sentence-5)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
For example, a call that acquires a mutex will
|
||||
perform an acquire operation on the locations comprising the mutex[.](#3.sentence-6)
|
||||
|
||||
Correspondingly, a call that releases the same mutex will perform a release
|
||||
operation on those same locations[.](#3.sentence-7)
|
||||
|
||||
Informally, performing a release operation onA forces priorside effects on other memory locations to become visible
|
||||
to other threads that later perform a consume or an acquire operation onA[.](#3.sentence-8)
|
||||
|
||||
âRelaxedâ atomic operations are not synchronization operations even
|
||||
though, like synchronization operations, they cannot contribute to data races[.](#3.sentence-9)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6664)
|
||||
|
||||
All modifications to a particular atomic object M occur in some
|
||||
particular total order, called the [*modification order*](#def:modification_order "6.10.2.2 Data races [intro.races]") of M[.](#4.sentence-1)
|
||||
|
||||
[*Note [4](#note-4)*:
|
||||
|
||||
There is a separate order for each
|
||||
atomic object[.](#4.sentence-2)
|
||||
|
||||
There is no requirement that these can be combined into a single
|
||||
total order for all objects[.](#4.sentence-3)
|
||||
|
||||
In general this will be impossible since different
|
||||
threads can observe modifications to different objects in inconsistent orders[.](#4.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6674)
|
||||
|
||||
A [*release sequence*](#def:release_sequence "6.10.2.2 Data races [intro.races]") headed
|
||||
by a release operation A on an atomic object M is a maximal contiguous sub-sequence ofside effects in the modification order of M,
|
||||
where the first operation is A, and
|
||||
every subsequent operation is an atomic read-modify-write operation[.](#5.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6683)
|
||||
|
||||
Certain library calls [*synchronize with*](#def:synchronize_with "6.10.2.2 Data races [intro.races]") other library calls performed by
|
||||
another thread[.](#6.sentence-1)
|
||||
|
||||
For example, an atomic store-release synchronizes with a
|
||||
load-acquire that takes its value from the store ([[atomics.order]](atomics.order "32.5.4 Order and consistency"))[.](#6.sentence-2)
|
||||
|
||||
[*Note [5](#note-5)*:
|
||||
|
||||
Except in the specified cases, reading a later value does not
|
||||
necessarily ensure visibility as described below[.](#6.sentence-3)
|
||||
|
||||
Such a requirement would
|
||||
sometimes interfere with efficient implementation[.](#6.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Note [6](#note-6)*:
|
||||
|
||||
The
|
||||
specifications of the synchronization operations define when one reads the value
|
||||
written by another[.](#6.sentence-5)
|
||||
|
||||
For atomic objects, the definition is clear[.](#6.sentence-6)
|
||||
|
||||
All operations
|
||||
on a given mutex occur in a single total order[.](#6.sentence-7)
|
||||
|
||||
Each mutex acquisition âreads
|
||||
the value writtenâ by the last mutex release[.](#6.sentence-8)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6700)
|
||||
|
||||
An evaluation A [*happens before*](#def:happens_before "6.10.2.2 Data races [intro.races]") an evaluation B (or, equivalently, B happens after A)
|
||||
if either
|
||||
|
||||
- [(7.1)](#7.1)
|
||||
|
||||
A is sequenced before B, or
|
||||
|
||||
- [(7.2)](#7.2)
|
||||
|
||||
A synchronizes with B, or
|
||||
|
||||
- [(7.3)](#7.3)
|
||||
|
||||
A happens before X and X happens before B[.](#7.sentence-1)
|
||||
|
||||
[*Note [7](#note-7)*:
|
||||
|
||||
An evaluation does not happen before itself[.](#7.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6713)
|
||||
|
||||
An evaluation A [*strongly happens before*](#def:strongly_happens_before "6.10.2.2 Data races [intro.races]") an evaluation D if, either
|
||||
|
||||
- [(8.1)](#8.1)
|
||||
|
||||
A is sequenced before D, or
|
||||
|
||||
- [(8.2)](#8.2)
|
||||
|
||||
A synchronizes with D, and
|
||||
both A and D are
|
||||
sequentially consistent atomic operations ([[atomics.order]](atomics.order "32.5.4 Order and consistency")), or
|
||||
|
||||
- [(8.3)](#8.3)
|
||||
|
||||
there are evaluations B and C such that A is sequenced before B,B happens before C, andC is sequenced before D, or
|
||||
|
||||
- [(8.4)](#8.4)
|
||||
|
||||
there is an evaluation B such thatA strongly happens before B, andB strongly happens before D[.](#8.sentence-1)
|
||||
|
||||
[*Note [8](#note-8)*:
|
||||
|
||||
Informally, if A strongly happens before B,
|
||||
then A appears to be evaluated before B in all contexts[.](#8.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6735)
|
||||
|
||||
A [*visible side effect*](#def:side_effects,visible "6.10.2.2 Data races [intro.races]") A on a scalar object or bit-field M with respect to a value computation B of M satisfies the
|
||||
conditions:
|
||||
|
||||
- [(9.1)](#9.1)
|
||||
|
||||
A happens before B and
|
||||
|
||||
- [(9.2)](#9.2)
|
||||
|
||||
there is no otherside effect X to M such that A happens before X and X happens before B[.](#9.sentence-1)
|
||||
|
||||
The value of a non-atomic scalar object or bit-field M, as determined by
|
||||
evaluation B, is the value stored by thevisible side effect A[.](#9.sentence-2)
|
||||
|
||||
[*Note [9](#note-9)*:
|
||||
|
||||
If there is ambiguity about which side effect to a
|
||||
non-atomic object or bit-field is visible, then the behavior is either
|
||||
unspecified or undefined[.](#9.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Note [10](#note-10)*:
|
||||
|
||||
This states that operations on
|
||||
ordinary objects are not visibly reordered[.](#9.sentence-4)
|
||||
|
||||
This is not actually detectable
|
||||
without data races, but is needed to ensure that data races, as defined
|
||||
below, and with suitable restrictions on the use of atomics, correspond to data
|
||||
races in a simple interleaved (sequentially consistent) execution[.](#9.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6764)
|
||||
|
||||
The value of an
|
||||
atomic object M, as determined by evaluation B, is the value
|
||||
stored by some unspecified
|
||||
side effect A that modifies M, where B does not happen
|
||||
before A[.](#10.sentence-1)
|
||||
|
||||
[*Note [11](#note-11)*:
|
||||
|
||||
The set of such side effects is also restricted by the rest of the rules
|
||||
described here, and in particular, by the coherence requirements below[.](#10.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6775)
|
||||
|
||||
If an operation A that modifies an atomic object M happens before
|
||||
an operation B that modifies M, then A is earlier
|
||||
than B in the modification order of M[.](#11.sentence-1)
|
||||
|
||||
[*Note [12](#note-12)*:
|
||||
|
||||
This requirement is known as write-write coherence[.](#11.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6784)
|
||||
|
||||
If avalue computation A of an atomic object M happens before a
|
||||
value computation B of M, and A takes its value from a side
|
||||
effect X on M, then the value computed by B is either
|
||||
the value stored by X or the value stored by aside effect Y on M,
|
||||
where Y follows X in the modification order of M[.](#12.sentence-1)
|
||||
|
||||
[*Note [13](#note-13)*:
|
||||
|
||||
This requirement is known as read-read coherence[.](#12.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6799)
|
||||
|
||||
If avalue computation A of an atomic object M happens before an
|
||||
operation B that modifies M, then A takes its value from a side
|
||||
effect X on M, where X precedes B in the
|
||||
modification order of M[.](#13.sentence-1)
|
||||
|
||||
[*Note [14](#note-14)*:
|
||||
|
||||
This requirement is known as
|
||||
read-write coherence[.](#13.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[14](#14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6812)
|
||||
|
||||
If aside effect X on an atomic object M happens before a value
|
||||
computation B of M, then the evaluation B takes its
|
||||
value from X or from aside effect Y that follows X in the modification order of M[.](#14.sentence-1)
|
||||
|
||||
[*Note [15](#note-15)*:
|
||||
|
||||
This requirement is known as write-read coherence[.](#14.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[15](#15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6825)
|
||||
|
||||
[*Note [16](#note-16)*:
|
||||
|
||||
The four preceding coherence requirements effectively disallow
|
||||
compiler reordering of atomic operations to a single object, even if both
|
||||
operations are relaxed loads[.](#15.sentence-1)
|
||||
|
||||
This effectively makes the cache coherence
|
||||
guarantee provided by most hardware available to C++ atomic operations[.](#15.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[16](#16)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6833)
|
||||
|
||||
[*Note [17](#note-17)*:
|
||||
|
||||
The value observed by a load of an atomic depends on the âhappens
|
||||
beforeâ relation, which depends on the values observed by loads of atomics[.](#16.sentence-1)
|
||||
|
||||
The intended reading is that there must exist an
|
||||
association of atomic loads with modifications they observe that, together with
|
||||
suitably chosen modification orders and the âhappens beforeâ relation derived
|
||||
as described above, satisfy the resulting constraints as imposed here[.](#16.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[17](#17)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6843)
|
||||
|
||||
Two actions are [*potentially concurrent*](#def:potentially_concurrent "6.10.2.2 Data races [intro.races]") if
|
||||
|
||||
- [(17.1)](#17.1)
|
||||
|
||||
they are performed by different threads, or
|
||||
|
||||
- [(17.2)](#17.2)
|
||||
|
||||
they are unsequenced, at least one is performed by a signal handler, and
|
||||
they are not both performed by the same signal handler invocation[.](#17.sentence-1)
|
||||
|
||||
The execution of a program contains a [*data race*](#def:data_race "6.10.2.2 Data races [intro.races]") if it contains two
|
||||
potentially concurrent conflicting actions, at least one of which is not atomic,
|
||||
and neither happens before the other,
|
||||
except for the special case for signal handlers described below[.](#17.sentence-2)
|
||||
|
||||
Any such data race results in undefined
|
||||
behavior[.](#17.sentence-3)
|
||||
|
||||
[*Note [18](#note-18)*:
|
||||
|
||||
It can be shown that programs that correctly use mutexes
|
||||
and memory_order::seq_cst operations to prevent all data races and use no
|
||||
other synchronization operations behave as if the operations executed by their
|
||||
constituent threads were simply interleaved, with eachvalue computation of an
|
||||
object being taken from the lastside effect on that object in that
|
||||
interleaving[.](#17.sentence-4)
|
||||
|
||||
This is normally referred to as âsequential consistencyâ[.](#17.sentence-5)
|
||||
|
||||
However, this applies only to data-race-free programs, and data-race-free
|
||||
programs cannot observe most program transformations that do not change
|
||||
single-threaded program semantics[.](#17.sentence-6)
|
||||
|
||||
In fact, most single-threaded program
|
||||
transformations remain possible, since any program that behaves
|
||||
differently as a result has undefined behavior[.](#17.sentence-7)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[18](#18)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6874)
|
||||
|
||||
Two accesses to the same non-bit-field object
|
||||
of type volatile std::sig_atomic_t do not
|
||||
result in a data race if both occur in the same thread, even if one or more
|
||||
occurs in a signal handler[.](#18.sentence-1)
|
||||
|
||||
For each signal handler invocation, evaluations
|
||||
performed by the thread invoking a signal handler can be divided into two
|
||||
groups A and B, such that no evaluations inB happen before evaluations in A, and the
|
||||
evaluations of such volatile std::sig_atomic_t objects take values as though
|
||||
all evaluations in A happened before the execution of the signal
|
||||
handler and the execution of the signal handler happened before all evaluations
|
||||
in B[.](#18.sentence-2)
|
||||
|
||||
[19](#19)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6887)
|
||||
|
||||
[*Note [19](#note-19)*:
|
||||
|
||||
Compiler transformations that introduce assignments to a potentially
|
||||
shared memory location that would not be modified by the abstract machine are
|
||||
generally precluded by this document, since such an assignment might overwrite
|
||||
another assignment by a different thread in cases in which an abstract machine
|
||||
execution would not have encountered a data race[.](#19.sentence-1)
|
||||
|
||||
This includes implementations
|
||||
of data member assignment that overwrite adjacent members in separate memory
|
||||
locations[.](#19.sentence-2)
|
||||
|
||||
Reordering of atomic loads in cases in which the atomics in question
|
||||
might alias is also generally precluded, since this could violate the coherence
|
||||
rules[.](#19.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[20](#20)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6900)
|
||||
|
||||
[*Note [20](#note-20)*:
|
||||
|
||||
It is possible that transformations that introduce a speculative read of a potentially
|
||||
shared memory location do not preserve the semantics of the C++ program as
|
||||
defined in this document, since they potentially introduce a data race[.](#20.sentence-1)
|
||||
|
||||
However,
|
||||
they are typically valid in the context of an optimizing compiler that targets a
|
||||
specific machine with well-defined semantics for data races[.](#20.sentence-2)
|
||||
|
||||
They would be
|
||||
invalid for a hypothetical machine that is not tolerant of races or provides
|
||||
hardware race detection[.](#20.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
Reference in New Issue
Block a user