1781 lines
77 KiB
Markdown
1781 lines
77 KiB
Markdown
[basic.exec]
|
||
|
||
# 6 Basics [[basic]](./#basic)
|
||
|
||
## 6.10 Program execution [basic.exec]
|
||
|
||
### [6.10.1](#intro.execution) Sequential execution [[intro.execution]](intro.execution)
|
||
|
||
[1](#intro.execution-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6225)
|
||
|
||
An instance of each object with [automatic storage
|
||
duration](basic.stc.auto "6.8.6.4 Automatic storage duration [basic.stc.auto]") is associated with each entry into its
|
||
block[.](#intro.execution-1.sentence-1)
|
||
|
||
Such an object exists and retains its last-stored value during
|
||
the execution of the block and while the block is suspended (by a call
|
||
of a function, suspension of a coroutine ([[expr.await]](expr.await "7.6.2.4 Await")), or receipt of a signal)[.](#intro.execution-1.sentence-2)
|
||
|
||
[2](#intro.execution-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6232)
|
||
|
||
A [*constituent expression*](#def:constituent_expression "6.10.1 Sequential execution [intro.execution]") is defined as follows:
|
||
|
||
- [(2.1)](#intro.execution-2.1)
|
||
|
||
The constituent expression of an expression is that expression[.](#intro.execution-2.1.sentence-1)
|
||
|
||
- [(2.2)](#intro.execution-2.2)
|
||
|
||
The constituent expression of a conversion is
|
||
the corresponding implicit function call, if any, or
|
||
the converted expression otherwise[.](#intro.execution-2.2.sentence-1)
|
||
|
||
- [(2.3)](#intro.execution-2.3)
|
||
|
||
The constituent expressions of a [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]") or
|
||
of a (possibly parenthesized) [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") are the constituent expressions of the elements of the respective list[.](#intro.execution-2.3.sentence-1)
|
||
|
||
- [(2.4)](#intro.execution-2.4)
|
||
|
||
The constituent expressions of a [*brace-or-equal-initializer*](dcl.init.general#nt:brace-or-equal-initializer "9.5.1 General [dcl.init.general]") of the form = [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [dcl.init.general]") are the constituent expressions of the [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [dcl.init.general]")[.](#intro.execution-2.4.sentence-1)
|
||
|
||
[*Example [1](#intro.execution-example-1)*: struct A { int x; };struct B { int y; struct A a; };
|
||
B b = { 5, { 1+1 } };
|
||
|
||
The constituent expressions of the [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]") used for the initialization of b are 5 and 1+1[.](#intro.execution-2.sentence-2)
|
||
|
||
â *end example*]
|
||
|
||
[3](#intro.execution-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6260)
|
||
|
||
The [*immediate subexpressions*](#def:immediate_subexpression "6.10.1 Sequential execution [intro.execution]") of an expression E are
|
||
|
||
- [(3.1)](#intro.execution-3.1)
|
||
|
||
the constituent expressions of E's operands ([[expr.prop]](expr.prop "7.2 Properties of expressions")),
|
||
|
||
- [(3.2)](#intro.execution-3.2)
|
||
|
||
any function call that E implicitly invokes,
|
||
|
||
- [(3.3)](#intro.execution-3.3)
|
||
|
||
if E is a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") ([[expr.prim.lambda]](expr.prim.lambda "7.5.6 Lambda expressions")),
|
||
the initialization of the entities captured by copy and
|
||
the constituent expressions of the [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]") of the [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")*s*,
|
||
|
||
- [(3.4)](#intro.execution-3.4)
|
||
|
||
if E is a [function call](expr.call "7.6.1.3 Function call [expr.call]") or implicitly invokes a function,
|
||
the constituent expressions of each default argument ([[dcl.fct.default]](dcl.fct.default "9.3.4.7 Default arguments"))
|
||
used in the call, or
|
||
|
||
- [(3.5)](#intro.execution-3.5)
|
||
|
||
if E creates an aggregate object ([[dcl.init.aggr]](dcl.init.aggr "9.5.2 Aggregates")),
|
||
the constituent expressions of each default member initializer ([[class.mem]](class.mem "11.4 Class members"))
|
||
used in the initialization[.](#intro.execution-3.sentence-1)
|
||
|
||
[4](#intro.execution-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6281)
|
||
|
||
A [*subexpression*](#def:subexpression "6.10.1 Sequential execution [intro.execution]") of an expression E is
|
||
an immediate subexpression of E or
|
||
a subexpression of an immediate subexpression of E[.](#intro.execution-4.sentence-1)
|
||
|
||
[*Note [1](#intro.execution-note-1)*:
|
||
|
||
Expressions appearing in the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") of a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") are not subexpressions of the [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")[.](#intro.execution-4.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
The [*potentially-evaluated subexpressions*](#def:subexpression,potentially-evaluated "6.10.1 Sequential execution [intro.execution]") of
|
||
an expression, conversion, or [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]") E are
|
||
|
||
- [(4.1)](#intro.execution-4.1)
|
||
|
||
the constituent expressions of E and
|
||
|
||
- [(4.2)](#intro.execution-4.2)
|
||
|
||
the subexpressions thereof that
|
||
are not subexpressions of a nested unevaluated operand ([[expr.context]](expr.context#term.unevaluated.operand "7.2.3 Context dependence"))[.](#intro.execution-4.sentence-3)
|
||
|
||
[5](#intro.execution-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6299)
|
||
|
||
A [*full-expression*](#def:full-expression "6.10.1 Sequential execution [intro.execution]") is
|
||
|
||
- [(5.1)](#intro.execution-5.1)
|
||
|
||
an [unevaluated operand](expr.context#def:unevaluated_operand "7.2.3 Context dependence [expr.context]"),
|
||
|
||
- [(5.2)](#intro.execution-5.2)
|
||
|
||
a [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") ([[expr.const]](expr.const "7.7 Constant expressions")),
|
||
|
||
- [(5.3)](#intro.execution-5.3)
|
||
|
||
an immediate invocation ([[expr.const]](expr.const "7.7 Constant expressions")),
|
||
|
||
- [(5.4)](#intro.execution-5.4)
|
||
|
||
an [*init-declarator*](dcl.decl.general#nt:init-declarator "9.3.1 General [dcl.decl.general]") ([[dcl.decl]](dcl.decl "9.3 Declarators"))
|
||
(including such introduced by a structured binding ([[dcl.struct.bind]](dcl.struct.bind "9.7 Structured binding declarations"))) or
|
||
a [*mem-initializer*](class.base.init#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") ([[class.base.init]](class.base.init "11.9.3 Initializing bases and members")),
|
||
including the constituent expressions of the initializer,
|
||
|
||
- [(5.5)](#intro.execution-5.5)
|
||
|
||
an invocation of a destructor generated at the end of the lifetime
|
||
of an object other than a temporary object ([[class.temporary]](class.temporary "6.8.7 Temporary objects"))
|
||
whose lifetime has not been extended,
|
||
|
||
- [(5.6)](#intro.execution-5.6)
|
||
|
||
the predicate of a contract assertion ([[basic.contract]](basic.contract "6.11 Contract assertions")), or
|
||
|
||
- [(5.7)](#intro.execution-5.7)
|
||
|
||
an expression that is not a subexpression of another expression and
|
||
that is not otherwise part of a full-expression[.](#intro.execution-5.sentence-1)
|
||
|
||
If a language construct is defined to produce an implicit call of a function,
|
||
a use of the language construct is considered to be an expression
|
||
for the purposes of this definition[.](#intro.execution-5.sentence-2)
|
||
|
||
Conversions applied to the result of an expression in order to satisfy the requirements
|
||
of the language construct in which the expression appears
|
||
are also considered to be part of the full-expression[.](#intro.execution-5.sentence-3)
|
||
|
||
For an initializer, performing the initialization of the entity
|
||
(including evaluating default member initializers of an aggregate)
|
||
is also considered part of the full-expression[.](#intro.execution-5.sentence-4)
|
||
|
||
[*Example [2](#intro.execution-example-2)*: struct S { S(int i): I(i) { } // full-expression is initialization of Iint& v() { return I; }~S() noexcept(false) { }private:int I;};
|
||
|
||
S s1(1); // full-expression comprises call of S::S(int)void f() { S s2 = 2; // full-expression comprises call of S::S(int)if (S(3).v()) // full-expression includes lvalue-to-rvalue and int to bool conversions,// performed before temporary is deleted at end of full-expression{ }bool b = noexcept(S(4)); // exception specification of destructor of S considered for noexcept// full-expression is destruction of s2 at end of block}struct B { B(S = S(0));};
|
||
B b[2] = { B(), B() }; // full-expression is the entire initialization// including the destruction of temporaries â *end example*]
|
||
|
||
[6](#intro.execution-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6360)
|
||
|
||
[*Note [2](#intro.execution-note-2)*:
|
||
|
||
The evaluation of a full-expression can include the
|
||
evaluation of subexpressions that are not lexically part of the
|
||
full-expression[.](#intro.execution-6.sentence-1)
|
||
|
||
For example, subexpressions involved in evaluating
|
||
default arguments ([[dcl.fct.default]](dcl.fct.default "9.3.4.7 Default arguments")) are considered to
|
||
be created in the expression that calls the function, not the expression
|
||
that defines the default argument[.](#intro.execution-6.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[7](#intro.execution-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6370)
|
||
|
||
Reading an object designated by a volatile glvalue ([[basic.lval]](basic.lval "7.2.1 Value category")),
|
||
modifying an object,
|
||
producing an injected declaration ([[expr.const]](expr.const "7.7 Constant expressions")),
|
||
calling a library I/O function, or
|
||
calling a function that does any of those operations
|
||
are all [*side effects*](#def:side_effects "6.10.1 Sequential execution [intro.execution]"),
|
||
which are changes in the state of the execution or translation environment[.](#intro.execution-7.sentence-1)
|
||
|
||
[*Evaluation*](#def:evaluation "6.10.1 Sequential execution [intro.execution]") of an expression (or a
|
||
subexpression) in general includes both value computations (including
|
||
determining the identity of an object for glvalue evaluation and fetching
|
||
a value previously assigned to an object for prvalue evaluation) and
|
||
initiation of side effects[.](#intro.execution-7.sentence-2)
|
||
|
||
When a call to a library I/O function
|
||
returns or an access through a volatile glvalue is evaluated, the side
|
||
effect is considered complete, even though some external actions implied
|
||
by the call (such as the I/O itself) or by the volatile access
|
||
may not have completed yet[.](#intro.execution-7.sentence-3)
|
||
|
||
[8](#intro.execution-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6389)
|
||
|
||
[*Sequenced before*](#def:sequenced_before "6.10.1 Sequential execution [intro.execution]") is an asymmetric, transitive, pair-wise relation between
|
||
evaluations executed by a single thread ([[intro.multithread]](#intro.multithread "6.10.2 Multi-threaded executions and data races")), which induces
|
||
a partial order among those evaluations[.](#intro.execution-8.sentence-1)
|
||
|
||
Given any two evaluations *A* and*B*, if *A* is sequenced before *B* (or, equivalently, *B* is [*sequenced after*](#def:sequenced_after "6.10.1 Sequential execution [intro.execution]") *A*),
|
||
then the execution of*A* shall precede the execution of *B*[.](#intro.execution-8.sentence-2)
|
||
|
||
If *A* is not sequenced
|
||
before *B* and *B* is not sequenced before *A*, then *A* and*B* are [*unsequenced*](#def:unsequenced "6.10.1 Sequential execution [intro.execution]")[.](#intro.execution-8.sentence-3)
|
||
|
||
[*Note [3](#intro.execution-note-3)*:
|
||
|
||
The execution of unsequenced
|
||
evaluations can overlap[.](#intro.execution-8.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
Evaluations *A* and *B* are[*indeterminately sequenced*](#def:indeterminately_sequenced "6.10.1 Sequential execution [intro.execution]") when either *A* is sequenced before*B* or *B* is sequenced before *A*, but it is unspecified which[.](#intro.execution-8.sentence-5)
|
||
|
||
[*Note [4](#intro.execution-note-4)*:
|
||
|
||
Indeterminately sequenced evaluations cannot overlap, but either
|
||
can be executed first[.](#intro.execution-8.sentence-6)
|
||
|
||
â *end note*]
|
||
|
||
An expression *X* is said to be sequenced before
|
||
an expression *Y* if
|
||
every value computation and every side effect
|
||
associated with the expression *X* is sequenced before
|
||
every value computation and every side effect
|
||
associated with the expression *Y*[.](#intro.execution-8.sentence-7)
|
||
|
||
[9](#intro.execution-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6419)
|
||
|
||
Everyvalue computation andside effect associated with a full-expression is
|
||
sequenced before every value computation and side effect associated with the
|
||
next full-expression to be evaluated[.](#intro.execution-9.sentence-1)[35](#footnote-35 "As specified in [class.temporary], after a full-expression is evaluated, a sequence of zero or more invocations of destructor functions for temporary objects takes place, usually in reverse order of the construction of each temporary object.")
|
||
|
||
[10](#intro.execution-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6434)
|
||
|
||
Except where noted, evaluations of operands of individual operators and
|
||
of subexpressions of individual expressions are unsequenced[.](#intro.execution-10.sentence-1)
|
||
|
||
[*Note [5](#intro.execution-note-5)*:
|
||
|
||
In an expression that is evaluated more than once during the execution
|
||
of a program, unsequenced and indeterminately sequenced evaluations of
|
||
its subexpressions need not be performed consistently in different
|
||
evaluations[.](#intro.execution-10.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
The value computations of the operands of an
|
||
operator are sequenced before the value computation of the result of the
|
||
operator[.](#intro.execution-10.sentence-3)
|
||
|
||
The behavior is undefined if
|
||
|
||
- [(10.1)](#intro.execution-10.1)
|
||
|
||
a side effect on a memory location ([[intro.memory]](intro.memory "6.8.1 Memory model")) or
|
||
|
||
- [(10.2)](#intro.execution-10.2)
|
||
|
||
starting or ending the lifetime of an object in a memory location
|
||
|
||
is unsequenced relative to
|
||
|
||
- [(10.3)](#intro.execution-10.3)
|
||
|
||
another side effect on the same memory location,
|
||
|
||
- [(10.4)](#intro.execution-10.4)
|
||
|
||
starting or ending the lifetime of an object occupying storage that
|
||
overlaps with the memory location, or
|
||
|
||
- [(10.5)](#intro.execution-10.5)
|
||
|
||
a value computation using the value of any object in the same memory location,
|
||
|
||
and the two evaluations are not potentially concurrent ([[intro.multithread]](#intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#intro.execution-10.sentence-4)
|
||
|
||
[*Note [6](#intro.execution-note-6)*:
|
||
|
||
Starting the lifetime of an object in a memory location can end the lifetime of
|
||
objects in other memory locations ([[basic.life]](basic.life "6.8.4 Lifetime"))[.](#intro.execution-10.sentence-5)
|
||
|
||
â *end note*]
|
||
|
||
[*Note [7](#intro.execution-note-7)*:
|
||
|
||
The next subclause imposes similar, but more complex restrictions on
|
||
potentially concurrent computations[.](#intro.execution-10.sentence-6)
|
||
|
||
â *end note*]
|
||
|
||
[*Example [3](#intro.execution-example-3)*: void g(int i) { i = 7, i++, i++; // i becomes 9 i = i++ + 1; // the value of i is incremented i = i++ + i; // undefined behavior i = i + 1; // the value of i is incrementedunion U { int x, y; } u; (u.x = 1, 0) + (u.y = 2, 0); // undefined behavior} â *end example*]
|
||
|
||
[11](#intro.execution-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6490)
|
||
|
||
When invoking a function *f* (whether or not the function is inline),
|
||
every argument expression and
|
||
the postfix expression designating *f* are sequenced before
|
||
every precondition assertion of *f* ([[dcl.contract.func]](dcl.contract.func "9.4.1 General")),
|
||
which in turn are sequenced before
|
||
every expression or statement
|
||
in the body of *f*,
|
||
which in turn are sequenced before
|
||
every postcondition assertion of *f*[.](#intro.execution-11.sentence-1)
|
||
|
||
[12](#intro.execution-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6502)
|
||
|
||
For each
|
||
|
||
- [(12.1)](#intro.execution-12.1)
|
||
|
||
function invocation,
|
||
|
||
- [(12.2)](#intro.execution-12.2)
|
||
|
||
evaluation of an [*await-expression*](expr.await#nt:await-expression "7.6.2.4 Await [expr.await]") ([[expr.await]](expr.await "7.6.2.4 Await")), or
|
||
|
||
- [(12.3)](#intro.execution-12.3)
|
||
|
||
evaluation of a [*throw-expression*](expr.throw#nt:throw-expression "7.6.18 Throwing an exception [expr.throw]") ([[expr.throw]](expr.throw "7.6.18 Throwing an exception"))
|
||
|
||
*F*,
|
||
each evaluation that does not occur within *F* but is evaluated on the same thread and as part of the same signal handler (if any)
|
||
is either sequenced before all evaluations that occur within *F* or sequenced after all evaluations that occur within *F*;[36](#footnote-36 "In other words, function executions do not interleave with each other.") if *F* invokes or resumes a coroutine ([[expr.await]](expr.await "7.6.2.4 Await")),
|
||
only evaluations
|
||
subsequent to the previous suspension (if any) and
|
||
prior to the next suspension (if any)
|
||
are considered to occur within *F*[.](#intro.execution-12.sentence-1)
|
||
|
||
[13](#intro.execution-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6524)
|
||
|
||
Several contexts in C++ cause evaluation of a function call, even
|
||
though no corresponding function call syntax appears in the translation
|
||
unit[.](#intro.execution-13.sentence-1)
|
||
|
||
[*Example [4](#intro.execution-example-4)*:
|
||
|
||
Evaluation of a [*new-expression*](expr.new#nt:new-expression "7.6.2.8 New [expr.new]") invokes one or more allocation
|
||
and constructor functions; see [[expr.new]](expr.new "7.6.2.8 New")[.](#intro.execution-13.sentence-2)
|
||
|
||
For another example,
|
||
invocation of a conversion function ([[class.conv.fct]](class.conv.fct "11.4.8.3 Conversion functions")) can arise in
|
||
contexts in which no function call syntax appears[.](#intro.execution-13.sentence-3)
|
||
|
||
â *end example*]
|
||
|
||
[14](#intro.execution-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6535)
|
||
|
||
The sequencing constraints on the execution of the called function (as
|
||
described above) are features of the function calls as evaluated,
|
||
regardless of the syntax of the expression that calls the function[.](#intro.execution-14.sentence-1)
|
||
|
||
[15](#intro.execution-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6543)
|
||
|
||
If a signal handler is executed as a result of a call to the std::raise function, then the execution of the handler is sequenced after the invocation
|
||
of the std::raise function and before its return[.](#intro.execution-15.sentence-1)
|
||
|
||
[*Note [8](#intro.execution-note-8)*:
|
||
|
||
When a signal is received for another reason, the execution of the
|
||
signal handler is usually unsequenced with respect to the rest of the program[.](#intro.execution-15.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[16](#intro.execution-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6552)
|
||
|
||
During the evaluation of an expression
|
||
as a core constant expression ([[expr.const]](expr.const "7.7 Constant expressions")),
|
||
evaluations of operands of individual operators and
|
||
of subexpressions of individual expressions
|
||
that are otherwise either unsequenced or indeterminately sequenced
|
||
are evaluated in lexical order[.](#intro.execution-16.sentence-1)
|
||
|
||
[35)](#footnote-35)[35)](#footnoteref-35)
|
||
|
||
As specified
|
||
in [[class.temporary]](class.temporary "6.8.7 Temporary objects"), after a full-expression is evaluated, a sequence of
|
||
zero or more invocations of destructor functions for temporary objects takes
|
||
place, usually in reverse order of the construction of each temporary object[.](#footnote-35.sentence-1)
|
||
|
||
[36)](#footnote-36)[36)](#footnoteref-36)
|
||
|
||
In other words,
|
||
function executions do not interleave with each other[.](#footnote-36.sentence-1)
|
||
|
||
### [6.10.2](#intro.multithread) Multi-threaded executions and data races [[intro.multithread]](intro.multithread)
|
||
|
||
#### [6.10.2.1](#intro.multithread.general) General [[intro.multithread.general]](intro.multithread.general)
|
||
|
||
[1](#intro.multithread.general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6564)
|
||
|
||
A [*thread of execution*](#def:thread_of_execution "6.10.2.1 General [intro.multithread.general]") (also known as a [*thread*](#def:thread "6.10.2.1 General [intro.multithread.general]")) 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[.](#intro.multithread.general-1.sentence-1)
|
||
|
||
[*Note [1](#intro.multithread.general-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[.](#intro.multithread.general-1.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
Every thread in a program can
|
||
potentially use every object and function in a program[.](#intro.multithread.general-1.sentence-3)[37](#footnote-37 "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]).")
|
||
|
||
Under a hosted
|
||
implementation, a C++ program can have more than one thread running
|
||
concurrently[.](#intro.multithread.general-1.sentence-4)
|
||
|
||
The execution of each thread proceeds as defined by the remainder
|
||
of this document[.](#intro.multithread.general-1.sentence-5)
|
||
|
||
The execution of the entire program consists of an execution
|
||
of all of its threads[.](#intro.multithread.general-1.sentence-6)
|
||
|
||
[*Note [2](#intro.multithread.general-note-2)*:
|
||
|
||
Usually the execution can be viewed as an
|
||
interleaving of all its threads[.](#intro.multithread.general-1.sentence-7)
|
||
|
||
However, some kinds of atomic operations, for
|
||
example, allow executions inconsistent with a simple interleaving, as described
|
||
below[.](#intro.multithread.general-1.sentence-8)
|
||
|
||
â *end note*]
|
||
|
||
Under a freestanding implementation, it is implementation-defined whether a program can
|
||
have more than one thread of execution[.](#intro.multithread.general-1.sentence-9)
|
||
|
||
[2](#intro.multithread.general-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6600)
|
||
|
||
For a signal handler that is not executed as a result of a call to thestd::raise function, it is unspecified which thread of execution
|
||
contains the signal handler invocation[.](#intro.multithread.general-2.sentence-1)
|
||
|
||
[37)](#footnote-37)[37)](#footnoteref-37)
|
||
|
||
An object
|
||
with automatic or thread storage duration ([[basic.stc]](basic.stc "6.8.6 Storage duration")) is associated with
|
||
one specific thread, and can be accessed by a different thread only indirectly
|
||
through a pointer or reference ([[basic.compound]](basic.compound "6.9.4 Compound types"))[.](#footnote-37.sentence-1)
|
||
|
||
#### [6.10.2.2](#intro.races) Data races [[intro.races]](intro.races)
|
||
|
||
[1](#intro.races-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[.](#intro.races-1.sentence-1)
|
||
|
||
[*Note [1](#intro.races-note-1)*:
|
||
|
||
In some cases, there might instead be undefined behavior[.](#intro.races-1.sentence-2)
|
||
|
||
Much of this
|
||
subclause is motivated by the desire to support atomic operations with explicit
|
||
and detailed visibility constraints[.](#intro.races-1.sentence-3)
|
||
|
||
However, it also implicitly supports a
|
||
simpler view for more restricted programs[.](#intro.races-1.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[2](#intro.races-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)](#intro.races-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)](#intro.races-2.2)
|
||
|
||
starts or ends the lifetime of an object in a memory location
|
||
|
||
and the other one
|
||
|
||
- [(2.3)](#intro.races-2.3)
|
||
|
||
reads or modifies the same memory location or
|
||
|
||
- [(2.4)](#intro.races-2.4)
|
||
|
||
starts or ends the lifetime of an object occupying storage that
|
||
overlaps with the memory location[.](#intro.races-2.sentence-1)
|
||
|
||
[*Note [2](#intro.races-note-2)*:
|
||
|
||
A modification can still conflict
|
||
even if it does not alter the value of any bits[.](#intro.races-2.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[3](#intro.races-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[.](#intro.races-3.sentence-1)
|
||
|
||
These operations play a special role in making
|
||
assignments in one thread visible to another[.](#intro.races-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[.](#intro.races-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[.](#intro.races-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[.](#intro.races-3.sentence-5)
|
||
|
||
[*Note [3](#intro.races-note-3)*:
|
||
|
||
For example, a call that acquires a mutex will
|
||
perform an acquire operation on the locations comprising the mutex[.](#intro.races-3.sentence-6)
|
||
|
||
Correspondingly, a call that releases the same mutex will perform a release
|
||
operation on those same locations[.](#intro.races-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[.](#intro.races-3.sentence-8)
|
||
|
||
âRelaxedâ atomic operations are not synchronization operations even
|
||
though, like synchronization operations, they cannot contribute to data races[.](#intro.races-3.sentence-9)
|
||
|
||
â *end note*]
|
||
|
||
[4](#intro.races-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[.](#intro.races-4.sentence-1)
|
||
|
||
[*Note [4](#intro.races-note-4)*:
|
||
|
||
There is a separate order for each
|
||
atomic object[.](#intro.races-4.sentence-2)
|
||
|
||
There is no requirement that these can be combined into a single
|
||
total order for all objects[.](#intro.races-4.sentence-3)
|
||
|
||
In general this will be impossible since different
|
||
threads can observe modifications to different objects in inconsistent orders[.](#intro.races-4.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[5](#intro.races-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[.](#intro.races-5.sentence-1)
|
||
|
||
[6](#intro.races-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[.](#intro.races-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"))[.](#intro.races-6.sentence-2)
|
||
|
||
[*Note [5](#intro.races-note-5)*:
|
||
|
||
Except in the specified cases, reading a later value does not
|
||
necessarily ensure visibility as described below[.](#intro.races-6.sentence-3)
|
||
|
||
Such a requirement would
|
||
sometimes interfere with efficient implementation[.](#intro.races-6.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[*Note [6](#intro.races-note-6)*:
|
||
|
||
The
|
||
specifications of the synchronization operations define when one reads the value
|
||
written by another[.](#intro.races-6.sentence-5)
|
||
|
||
For atomic objects, the definition is clear[.](#intro.races-6.sentence-6)
|
||
|
||
All operations
|
||
on a given mutex occur in a single total order[.](#intro.races-6.sentence-7)
|
||
|
||
Each mutex acquisition âreads
|
||
the value writtenâ by the last mutex release[.](#intro.races-6.sentence-8)
|
||
|
||
â *end note*]
|
||
|
||
[7](#intro.races-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)](#intro.races-7.1)
|
||
|
||
A is sequenced before B, or
|
||
|
||
- [(7.2)](#intro.races-7.2)
|
||
|
||
A synchronizes with B, or
|
||
|
||
- [(7.3)](#intro.races-7.3)
|
||
|
||
A happens before X and X happens before B[.](#intro.races-7.sentence-1)
|
||
|
||
[*Note [7](#intro.races-note-7)*:
|
||
|
||
An evaluation does not happen before itself[.](#intro.races-7.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[8](#intro.races-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)](#intro.races-8.1)
|
||
|
||
A is sequenced before D, or
|
||
|
||
- [(8.2)](#intro.races-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)](#intro.races-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)](#intro.races-8.4)
|
||
|
||
there is an evaluation B such thatA strongly happens before B, andB strongly happens before D[.](#intro.races-8.sentence-1)
|
||
|
||
[*Note [8](#intro.races-note-8)*:
|
||
|
||
Informally, if A strongly happens before B,
|
||
then A appears to be evaluated before B in all contexts[.](#intro.races-8.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[9](#intro.races-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)](#intro.races-9.1)
|
||
|
||
A happens before B and
|
||
|
||
- [(9.2)](#intro.races-9.2)
|
||
|
||
there is no otherside effect X to M such that A happens before X and X happens before B[.](#intro.races-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[.](#intro.races-9.sentence-2)
|
||
|
||
[*Note [9](#intro.races-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[.](#intro.races-9.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[*Note [10](#intro.races-note-10)*:
|
||
|
||
This states that operations on
|
||
ordinary objects are not visibly reordered[.](#intro.races-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[.](#intro.races-9.sentence-5)
|
||
|
||
â *end note*]
|
||
|
||
[10](#intro.races-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[.](#intro.races-10.sentence-1)
|
||
|
||
[*Note [11](#intro.races-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[.](#intro.races-10.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[11](#intro.races-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[.](#intro.races-11.sentence-1)
|
||
|
||
[*Note [12](#intro.races-note-12)*:
|
||
|
||
This requirement is known as write-write coherence[.](#intro.races-11.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[12](#intro.races-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[.](#intro.races-12.sentence-1)
|
||
|
||
[*Note [13](#intro.races-note-13)*:
|
||
|
||
This requirement is known as read-read coherence[.](#intro.races-12.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[13](#intro.races-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[.](#intro.races-13.sentence-1)
|
||
|
||
[*Note [14](#intro.races-note-14)*:
|
||
|
||
This requirement is known as
|
||
read-write coherence[.](#intro.races-13.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[14](#intro.races-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[.](#intro.races-14.sentence-1)
|
||
|
||
[*Note [15](#intro.races-note-15)*:
|
||
|
||
This requirement is known as write-read coherence[.](#intro.races-14.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[15](#intro.races-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6825)
|
||
|
||
[*Note [16](#intro.races-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[.](#intro.races-15.sentence-1)
|
||
|
||
This effectively makes the cache coherence
|
||
guarantee provided by most hardware available to C++ atomic operations[.](#intro.races-15.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[16](#intro.races-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6833)
|
||
|
||
[*Note [17](#intro.races-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[.](#intro.races-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[.](#intro.races-16.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[17](#intro.races-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)](#intro.races-17.1)
|
||
|
||
they are performed by different threads, or
|
||
|
||
- [(17.2)](#intro.races-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[.](#intro.races-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[.](#intro.races-17.sentence-2)
|
||
|
||
Any such data race results in undefined
|
||
behavior[.](#intro.races-17.sentence-3)
|
||
|
||
[*Note [18](#intro.races-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[.](#intro.races-17.sentence-4)
|
||
|
||
This is normally referred to as âsequential consistencyâ[.](#intro.races-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[.](#intro.races-17.sentence-6)
|
||
|
||
In fact, most single-threaded program
|
||
transformations remain possible, since any program that behaves
|
||
differently as a result has undefined behavior[.](#intro.races-17.sentence-7)
|
||
|
||
â *end note*]
|
||
|
||
[18](#intro.races-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[.](#intro.races-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[.](#intro.races-18.sentence-2)
|
||
|
||
[19](#intro.races-19)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6887)
|
||
|
||
[*Note [19](#intro.races-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[.](#intro.races-19.sentence-1)
|
||
|
||
This includes implementations
|
||
of data member assignment that overwrite adjacent members in separate memory
|
||
locations[.](#intro.races-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[.](#intro.races-19.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[20](#intro.races-20)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6900)
|
||
|
||
[*Note [20](#intro.races-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[.](#intro.races-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[.](#intro.races-20.sentence-2)
|
||
|
||
They would be
|
||
invalid for a hypothetical machine that is not tolerant of races or provides
|
||
hardware race detection[.](#intro.races-20.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
#### [6.10.2.3](#intro.progress) Forward progress [[intro.progress]](intro.progress)
|
||
|
||
[1](#intro.progress-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6913)
|
||
|
||
The implementation may assume that any thread will eventually do one of the
|
||
following:
|
||
|
||
- [(1.1)](#intro.progress-1.1)
|
||
|
||
terminate,
|
||
|
||
- [(1.2)](#intro.progress-1.2)
|
||
|
||
invoke the function std::this_thread::yield ([[thread.thread.this]](thread.thread.this "32.4.5 Namespace this_thread")),
|
||
|
||
- [(1.3)](#intro.progress-1.3)
|
||
|
||
make a call to a library I/O function,
|
||
|
||
- [(1.4)](#intro.progress-1.4)
|
||
|
||
perform an access through a volatile glvalue,
|
||
|
||
- [(1.5)](#intro.progress-1.5)
|
||
|
||
perform an atomic or synchronization operation
|
||
other than an atomic modify-write operation ([[atomics.order]](atomics.order "32.5.4 Order and consistency")), or
|
||
|
||
- [(1.6)](#intro.progress-1.6)
|
||
|
||
continue execution of a trivial infinite loop ([[stmt.iter.general]](stmt.iter.general "8.6.1 General"))[.](#intro.progress-1.sentence-1)
|
||
|
||
[*Note [1](#intro.progress-note-1)*:
|
||
|
||
This is intended to allow compiler transformations
|
||
such as removal, merging, and reordering of empty loops,
|
||
even when termination cannot be proven[.](#intro.progress-1.sentence-2)
|
||
|
||
An affordance is made for trivial infinite loops,
|
||
which cannot be removed nor reordered[.](#intro.progress-1.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[2](#intro.progress-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6933)
|
||
|
||
Executions of atomic functions
|
||
that are either defined to be lock-free ([[atomics.flag]](atomics.flag "32.5.10 Flag type and operations"))
|
||
or indicated as lock-free ([[atomics.lockfree]](atomics.lockfree "32.5.5 Lock-free property"))
|
||
are [*lock-free executions*](#def:lock-free_execution "6.10.2.3 Forward progress [intro.progress]")[.](#intro.progress-2.sentence-1)
|
||
|
||
- [(2.1)](#intro.progress-2.1)
|
||
|
||
If there is only one thread that is not blocked ([[defns.block]](defns.block "3.6 block"))
|
||
in a standard library function,
|
||
a lock-free execution in that thread shall complete[.](#intro.progress-2.1.sentence-1)
|
||
[*Note [2](#intro.progress-note-2)*:
|
||
Concurrently executing threads
|
||
might prevent progress of a lock-free execution[.](#intro.progress-2.1.sentence-2)
|
||
For example,
|
||
this situation can occur
|
||
with load-locked store-conditional implementations[.](#intro.progress-2.1.sentence-3)
|
||
This property is sometimes termed obstruction-free[.](#intro.progress-2.1.sentence-4)
|
||
â *end note*]
|
||
|
||
- [(2.2)](#intro.progress-2.2)
|
||
|
||
When one or more lock-free executions run concurrently,
|
||
at least one should complete[.](#intro.progress-2.2.sentence-1)
|
||
[*Note [3](#intro.progress-note-3)*:
|
||
It is difficult for some implementations
|
||
to provide absolute guarantees to this effect,
|
||
since repeated and particularly inopportune interference
|
||
from other threads
|
||
could prevent forward progress,
|
||
e.g.,
|
||
by repeatedly stealing a cache line
|
||
for unrelated purposes
|
||
between load-locked and store-conditional instructions[.](#intro.progress-2.2.sentence-2)
|
||
For implementations that follow this recommendation and
|
||
ensure that such effects cannot indefinitely delay progress
|
||
under expected operating conditions,
|
||
such anomalies
|
||
can therefore safely be ignored by programmers[.](#intro.progress-2.2.sentence-3)
|
||
Outside this document,
|
||
this property is sometimes termed lock-free[.](#intro.progress-2.2.sentence-4)
|
||
â *end note*]
|
||
|
||
[3](#intro.progress-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6974)
|
||
|
||
During the execution of a thread of execution, each of the following is termed
|
||
an [*execution step*](#def:execution_step "6.10.2.3 Forward progress [intro.progress]"):
|
||
|
||
- [(3.1)](#intro.progress-3.1)
|
||
|
||
termination of the thread of execution,
|
||
|
||
- [(3.2)](#intro.progress-3.2)
|
||
|
||
performing an access through a volatile glvalue,
|
||
|
||
- [(3.3)](#intro.progress-3.3)
|
||
|
||
completion of a call to a library I/O function, or
|
||
|
||
- [(3.4)](#intro.progress-3.4)
|
||
|
||
completion of an atomic or synchronization operation
|
||
other than an atomic modify-write operation ([[atomics.order]](atomics.order "32.5.4 Order and consistency"))[.](#intro.progress-3.sentence-1)
|
||
|
||
[4](#intro.progress-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6985)
|
||
|
||
An invocation of a standard library function that blocks ([[defns.block]](defns.block "3.6 block"))
|
||
is considered to continuously execute execution steps while waiting for the
|
||
condition that it blocks on to be satisfied[.](#intro.progress-4.sentence-1)
|
||
|
||
[*Example [1](#intro.progress-example-1)*:
|
||
|
||
A library I/O function that blocks until the I/O operation is complete can
|
||
be considered to continuously check whether the operation is complete[.](#intro.progress-4.sentence-2)
|
||
|
||
Each
|
||
such check consists of one or more execution steps, for example using
|
||
observable behavior of the abstract machine[.](#intro.progress-4.sentence-3)
|
||
|
||
â *end example*]
|
||
|
||
[5](#intro.progress-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L6996)
|
||
|
||
[*Note [4](#intro.progress-note-4)*:
|
||
|
||
Because of this and the preceding requirement regarding what threads of execution
|
||
have to perform eventually, it follows that no thread of execution can execute
|
||
forever without an execution step occurring[.](#intro.progress-5.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[6](#intro.progress-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7003)
|
||
|
||
A thread of execution [*makes progress*](#def:make_progress,thread "6.10.2.3 Forward progress [intro.progress]") when an execution step occurs or a
|
||
lock-free execution does not complete because there are other concurrent threads
|
||
that are not blocked in a standard library function (see above)[.](#intro.progress-6.sentence-1)
|
||
|
||
[7](#intro.progress-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7009)
|
||
|
||
For a thread of execution providing [*concurrent forward progress guarantees*](#def:concurrent_forward_progress_guarantees "6.10.2.3 Forward progress [intro.progress]"),
|
||
the implementation ensures that the thread will eventually make progress for as
|
||
long as it has not terminated[.](#intro.progress-7.sentence-1)
|
||
|
||
[*Note [5](#intro.progress-note-5)*:
|
||
|
||
This applies regardless of whether or not other threads of execution (if any)
|
||
have been or are making progress[.](#intro.progress-7.sentence-2)
|
||
|
||
To eventually fulfill this requirement means that
|
||
this will happen in an unspecified but finite amount of time[.](#intro.progress-7.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[8](#intro.progress-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7020)
|
||
|
||
It is implementation-defined whether the
|
||
implementation-created thread of execution that executesmain ([[basic.start.main]](#basic.start.main "6.10.3.1 main function")) and the threads of execution created bystd::thread ([[thread.thread.class]](thread.thread.class "32.4.3 Class thread"))
|
||
or std::jthread ([[thread.jthread.class]](thread.jthread.class "32.4.4 Class jthread"))
|
||
provide concurrent forward progress guarantees[.](#intro.progress-8.sentence-1)
|
||
|
||
General-purpose implementations should provide these guarantees[.](#intro.progress-8.sentence-2)
|
||
|
||
[9](#intro.progress-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7030)
|
||
|
||
For a thread of execution providing [*parallel forward progress guarantees*](#def:parallel_forward_progress_guarantees "6.10.2.3 Forward progress [intro.progress]"),
|
||
the implementation is not required to ensure that the thread will eventually make
|
||
progress if it has not yet executed any execution step; once this thread has
|
||
executed a step, it provides concurrent forward progress guarantees[.](#intro.progress-9.sentence-1)
|
||
|
||
[10](#intro.progress-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7037)
|
||
|
||
[*Note [6](#intro.progress-note-6)*:
|
||
|
||
This does not specify a requirement for when to start this thread of execution,
|
||
which will typically be specified by the entity that creates this thread of
|
||
execution[.](#intro.progress-10.sentence-1)
|
||
|
||
For example, a thread of execution that provides concurrent forward
|
||
progress guarantees and executes tasks from a set of tasks in an arbitrary order,
|
||
one after the other, satisfies the requirements of parallel forward progress for
|
||
these tasks[.](#intro.progress-10.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[11](#intro.progress-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7047)
|
||
|
||
For a thread of execution providing [*weakly parallel forward progress
|
||
guarantees*](#def:weakly_parallel_forward_progress_guarantees "6.10.2.3 Forward progress [intro.progress]"), the implementation does not ensure that the thread will eventually
|
||
make progress[.](#intro.progress-11.sentence-1)
|
||
|
||
[12](#intro.progress-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7053)
|
||
|
||
[*Note [7](#intro.progress-note-7)*:
|
||
|
||
Threads of execution providing weakly parallel forward progress guarantees cannot
|
||
be expected to make progress regardless of whether other threads make progress or
|
||
not; however, blocking with forward progress guarantee delegation, as defined below,
|
||
can be used to ensure that such threads of execution make progress eventually[.](#intro.progress-12.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[13](#intro.progress-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7061)
|
||
|
||
Concurrent forward progress guarantees are stronger than parallel forward progress
|
||
guarantees, which in turn are stronger than weakly parallel forward progress
|
||
guarantees[.](#intro.progress-13.sentence-1)
|
||
|
||
[*Note [8](#intro.progress-note-8)*:
|
||
|
||
For example, some kinds of synchronization between threads of execution might only
|
||
make progress if the respective threads of execution provide parallel forward progress
|
||
guarantees, but will fail to make progress under weakly parallel guarantees[.](#intro.progress-13.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[14](#intro.progress-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7071)
|
||
|
||
When a thread of execution P is specified to[*block with forward progress guarantee delegation*](#def:block_(execution),with_forward_progress_guarantee_delegation "6.10.2.3 Forward progress [intro.progress]") on the completion of a set S of threads of execution,
|
||
then throughout the whole time of P being blocked on S,
|
||
the implementation shall ensure that the forward progress guarantees
|
||
provided by at least one thread of execution in S is at least as strong as P's forward progress guarantees[.](#intro.progress-14.sentence-1)
|
||
|
||
[*Note [9](#intro.progress-note-9)*:
|
||
|
||
It is unspecified which thread or threads of execution in S are chosen
|
||
and for which number of execution steps[.](#intro.progress-14.sentence-2)
|
||
|
||
The strengthening is not permanent and
|
||
not necessarily in place for the rest of the lifetime of the affected thread of
|
||
execution[.](#intro.progress-14.sentence-3)
|
||
|
||
As long as P is blocked, the implementation has to eventually
|
||
select and potentially strengthen a thread of execution in S[.](#intro.progress-14.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
Once a thread of execution in S terminates, it is removed from S[.](#intro.progress-14.sentence-5)
|
||
|
||
Once S is empty, P is unblocked[.](#intro.progress-14.sentence-6)
|
||
|
||
[15](#intro.progress-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7091)
|
||
|
||
[*Note [10](#intro.progress-note-10)*:
|
||
|
||
A thread of execution B thus can temporarily provide an effectively
|
||
stronger forward progress guarantee for a certain amount of time, due to a
|
||
second thread of execution A being blocked on it with forward
|
||
progress guarantee delegation[.](#intro.progress-15.sentence-1)
|
||
|
||
In turn, if B then blocks with
|
||
forward progress guarantee delegation on C, this can also temporarily
|
||
provide a stronger forward progress guarantee to C[.](#intro.progress-15.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[16](#intro.progress-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7101)
|
||
|
||
[*Note [11](#intro.progress-note-11)*:
|
||
|
||
If all threads of execution in S finish executing (e.g., they terminate
|
||
and do not use blocking synchronization incorrectly), then P's execution
|
||
of the operation that blocks with forward progress guarantee delegation will not
|
||
result in P's progress guarantee being effectively weakened[.](#intro.progress-16.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[17](#intro.progress-17)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7109)
|
||
|
||
[*Note [12](#intro.progress-note-12)*:
|
||
|
||
This does not remove any constraints regarding blocking synchronization for
|
||
threads of execution providing parallel or weakly parallel forward progress
|
||
guarantees because the implementation is not required to strengthen a particular
|
||
thread of execution whose too-weak progress guarantee is preventing overall progress[.](#intro.progress-17.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[18](#intro.progress-18)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7117)
|
||
|
||
An implementation should ensure that the last value (in modification order)
|
||
assigned by an atomic or synchronization operation will become visible to all
|
||
other threads in a finite period of time[.](#intro.progress-18.sentence-1)
|
||
|
||
### [6.10.3](#basic.start) Start and termination [[basic.start]](basic.start)
|
||
|
||
#### [6.10.3.1](#basic.start.main) main function [[basic.start.main]](basic.start.main)
|
||
|
||
[1](#basic.start.main-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7129)
|
||
|
||
A program shall contain exactly one function called main that belongs to the global scope[.](#basic.start.main-1.sentence-1)
|
||
|
||
Executing a program starts a main thread of execution ([[intro.multithread]](#intro.multithread "6.10.2 Multi-threaded executions and data races"), [[thread.threads]](thread.threads "32.4 Threads"))
|
||
in which the main function is invoked[.](#basic.start.main-1.sentence-2)
|
||
|
||
It is implementation-defined
|
||
whether a program in a freestanding environment is required to define a main function[.](#basic.start.main-1.sentence-3)
|
||
|
||
[*Note [1](#basic.start.main-note-1)*:
|
||
|
||
In a freestanding environment, startup and termination isimplementation-defined; startup contains the
|
||
execution of constructors for non-local objects with static storage duration;
|
||
termination contains the execution of destructors for objects with static storage
|
||
duration[.](#basic.start.main-1.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[2](#basic.start.main-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7147)
|
||
|
||
An implementation shall not predefine the main function[.](#basic.start.main-2.sentence-1)
|
||
|
||
Its type shall have C++ language linkage
|
||
and it shall have a declared return type of typeint, but otherwise its type is implementation-defined[.](#basic.start.main-2.sentence-2)
|
||
|
||
An implementation shall allow both
|
||
|
||
- [(2.1)](#basic.start.main-2.1)
|
||
|
||
a function of () returning int and
|
||
|
||
- [(2.2)](#basic.start.main-2.2)
|
||
|
||
a function of (int, pointer to pointer to char) returning int
|
||
|
||
as the type of main ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))[.](#basic.start.main-2.sentence-3)
|
||
|
||
In the latter form, for purposes of exposition, the first function
|
||
parameter is called argc and the second function parameter is
|
||
called argv, where argc shall be the number of
|
||
arguments passed to the program from the environment in which the
|
||
program is run[.](#basic.start.main-2.sentence-4)
|
||
|
||
Ifargc is nonzero these arguments shall be supplied inargv[0] through argv[argc - 1] as pointers to the initial
|
||
characters of null-terminated multibyte strings (ntmbss) ([[multibyte.strings]](multibyte.strings "16.3.3.3.4.3 Multibyte strings"))
|
||
and argv[0] shall be the pointer to
|
||
the initial character of an ntmbs that represents the name used to
|
||
invoke the program or ""[.](#basic.start.main-2.sentence-5)
|
||
|
||
The value of argc shall be
|
||
non-negative[.](#basic.start.main-2.sentence-6)
|
||
|
||
The value of argv[argc] shall be 0[.](#basic.start.main-2.sentence-7)
|
||
|
||
*Recommended practice*: Any further (optional) parameters should be added after argv[.](#basic.start.main-2.sentence-8)
|
||
|
||
[3](#basic.start.main-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7179)
|
||
|
||
The function main shall not be named by an expression[.](#basic.start.main-3.sentence-1)
|
||
|
||
The linkage ([[basic.link]](basic.link "6.7 Program and linkage")) of main isimplementation-defined[.](#basic.start.main-3.sentence-2)
|
||
|
||
A program that defines main as
|
||
deleted or that declares main to beinline, static, constexpr, or consteval is ill-formed[.](#basic.start.main-3.sentence-3)
|
||
|
||
The function main shall not be a coroutine ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4 Coroutine definitions"))[.](#basic.start.main-3.sentence-4)
|
||
|
||
The main function shall not be declared with a[*linkage-specification*](dcl.link#nt:linkage-specification "9.12 Linkage specifications [dcl.link]") ([[dcl.link]](dcl.link "9.12 Linkage specifications")) other than "C++"[.](#basic.start.main-3.sentence-5)
|
||
|
||
A program that declares
|
||
|
||
- [(3.1)](#basic.start.main-3.1)
|
||
|
||
a variable main that belongs to the global scope, or
|
||
|
||
- [(3.2)](#basic.start.main-3.2)
|
||
|
||
a function main that belongs to the global scope and
|
||
is attached to a named module, or
|
||
|
||
- [(3.3)](#basic.start.main-3.3)
|
||
|
||
a function template main that belongs to the global scope, or
|
||
|
||
- [(3.4)](#basic.start.main-3.4)
|
||
|
||
an entity named main with C language linkage (in any namespace)
|
||
|
||
is ill-formed[.](#basic.start.main-3.sentence-6)
|
||
|
||
The name main is
|
||
not otherwise reserved[.](#basic.start.main-3.sentence-7)
|
||
|
||
[*Example [1](#basic.start.main-example-1)*:
|
||
|
||
Member functions, classes, and
|
||
enumerations can be called main, as can entities in other
|
||
namespaces[.](#basic.start.main-3.sentence-8)
|
||
|
||
â *end example*]
|
||
|
||
[4](#basic.start.main-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7211)
|
||
|
||
Terminating the program
|
||
without leaving the current block (e.g., by calling the functionstd::exit(int) ([[support.start.term]](support.start.term "17.5 Startup and termination"))) does not destroy any
|
||
objects with automatic storage duration ([[class.dtor]](class.dtor "11.4.7 Destructors"))[.](#basic.start.main-4.sentence-1)
|
||
|
||
Ifstd::exit is invoked during the destruction of
|
||
an object with static or thread storage duration, the program has undefined
|
||
behavior[.](#basic.start.main-4.sentence-2)
|
||
|
||
[5](#basic.start.main-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7223)
|
||
|
||
A return statement ([[stmt.return]](stmt.return "8.8.4 The return statement")) in main has the effect of leaving the main function (destroying any objects with automatic storage duration
|
||
and evaluating any postcondition assertions of main)
|
||
and calling std::exit with the return value as the argument[.](#basic.start.main-5.sentence-1)
|
||
|
||
If control flows off the end of
|
||
the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") of main,
|
||
the effect is equivalent to a return with operand 0 (see also [[except.handle]](except.handle "14.4 Handling an exception"))[.](#basic.start.main-5.sentence-2)
|
||
|
||
#### [6.10.3.2](#basic.start.static) Static initialization [[basic.start.static]](basic.start.static)
|
||
|
||
[1](#basic.start.static-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7238)
|
||
|
||
Variables with static storage duration
|
||
are initialized as a consequence of program initiation[.](#basic.start.static-1.sentence-1)
|
||
|
||
Variables with
|
||
thread storage duration are initialized as a consequence of thread execution[.](#basic.start.static-1.sentence-2)
|
||
|
||
Within each of these phases of initiation, initialization occurs as follows[.](#basic.start.static-1.sentence-3)
|
||
|
||
[2](#basic.start.static-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7246)
|
||
|
||
[*Constant initialization*](#def:constant_initialization "6.10.3.2 Static initialization [basic.start.static]") is performed
|
||
if a variable with static or thread storage duration
|
||
is constant-initialized ([[expr.const]](expr.const "7.7 Constant expressions"))[.](#basic.start.static-2.sentence-1)
|
||
|
||
If constant initialization is not performed, a variable with static
|
||
storage duration ([[basic.stc.static]](basic.stc.static "6.8.6.2 Static storage duration")) or thread storage
|
||
duration ([[basic.stc.thread]](basic.stc.thread "6.8.6.3 Thread storage duration")) is zero-initialized ([[dcl.init]](dcl.init "9.5 Initializers"))[.](#basic.start.static-2.sentence-2)
|
||
|
||
Together, zero-initialization and constant initialization are called[*static initialization*](#def:initialization,static "6.10.3.2 Static initialization [basic.start.static]");
|
||
all other initialization is [*dynamic initialization*](#def:initialization,dynamic "6.10.3.2 Static initialization [basic.start.static]")[.](#basic.start.static-2.sentence-3)
|
||
|
||
All static initialization strongly happens before ([[intro.races]](#intro.races "6.10.2.2 Data races"))
|
||
any dynamic initialization[.](#basic.start.static-2.sentence-4)
|
||
|
||
[*Note [1](#basic.start.static-note-1)*:
|
||
|
||
The dynamic initialization of non-block variables is described
|
||
in [[basic.start.dynamic]](#basic.start.dynamic "6.10.3.3 Dynamic initialization of non-block variables"); that of static block variables is described
|
||
in [[stmt.dcl]](stmt.dcl "8.10 Declaration statement")[.](#basic.start.static-2.sentence-5)
|
||
|
||
â *end note*]
|
||
|
||
[3](#basic.start.static-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7266)
|
||
|
||
An implementation is permitted to perform the initialization of a
|
||
variable with static or thread storage duration as a static
|
||
initialization even if such initialization is not required to be done
|
||
statically, provided that
|
||
|
||
- [(3.1)](#basic.start.static-3.1)
|
||
|
||
the dynamic version of the initialization does not change the
|
||
value of any other object of static or thread storage duration
|
||
prior to its initialization, and
|
||
|
||
- [(3.2)](#basic.start.static-3.2)
|
||
|
||
the static version of the initialization produces the same value
|
||
in the initialized variable as would be produced by the dynamic
|
||
initialization if all variables not required to be initialized statically
|
||
were initialized dynamically[.](#basic.start.static-3.sentence-1)
|
||
|
||
[*Note [2](#basic.start.static-note-2)*:
|
||
|
||
As a consequence, if the initialization of an object obj1 refers to an
|
||
object obj2 potentially requiring dynamic initialization and defined
|
||
later in the same translation unit, it is unspecified whether the value of obj2 used
|
||
will be the value of the fully initialized obj2 (because obj2 was statically
|
||
initialized) or will be the value of obj2 merely zero-initialized[.](#basic.start.static-3.sentence-2)
|
||
|
||
For example,inline double fd() { return 1.0; }extern double d1;double d2 = d1; // unspecified:// either statically initialized to 0.0 or// dynamically initialized to 0.0 if d1 is// dynamically initialized, or 1.0 otherwisedouble d1 = fd(); // either initialized statically or dynamically to 1.0
|
||
|
||
â *end note*]
|
||
|
||
#### [6.10.3.3](#basic.start.dynamic) Dynamic initialization of non-block variables [[basic.start.dynamic]](basic.start.dynamic)
|
||
|
||
[1](#basic.start.dynamic-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7302)
|
||
|
||
Dynamic initialization of a non-block variable with static storage duration is
|
||
unordered if the variable is an implicitly or explicitly instantiated
|
||
specialization, is partially-ordered if the variable
|
||
is an inline variable that is not an implicitly or explicitly instantiated
|
||
specialization, and otherwise is ordered[.](#basic.start.dynamic-1.sentence-1)
|
||
|
||
[*Note [1](#basic.start.dynamic-note-1)*:
|
||
|
||
A non-inline explicit specialization of a templated variable
|
||
has ordered initialization[.](#basic.start.dynamic-1.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[2](#basic.start.dynamic-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7316)
|
||
|
||
A declaration D is[*appearance-ordered*](#def:appearance-ordered "6.10.3.3 Dynamic initialization of non-block variables [basic.start.dynamic]") before a declaration E if
|
||
|
||
- [(2.1)](#basic.start.dynamic-2.1)
|
||
|
||
D appears in the same translation unit as E, or
|
||
|
||
- [(2.2)](#basic.start.dynamic-2.2)
|
||
|
||
the translation unit containing E has an interface dependency on the translation unit containing D,
|
||
|
||
in either case prior to E[.](#basic.start.dynamic-2.sentence-1)
|
||
|
||
[3](#basic.start.dynamic-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7326)
|
||
|
||
Dynamic initialization of non-block variables V and W with static storage duration are ordered as follows:
|
||
|
||
- [(3.1)](#basic.start.dynamic-3.1)
|
||
|
||
If V and W have ordered initialization and
|
||
the definition of V is appearance-ordered before the definition of W, or
|
||
if V has partially-ordered initialization,W does not have unordered initialization, and
|
||
for every definition E of W there exists a definition D of V such that D is appearance-ordered before E, then
|
||
* [(3.1.1)](#basic.start.dynamic-3.1.1)
|
||
|
||
if the program does not start a thread ([[intro.multithread]](#intro.multithread "6.10.2 Multi-threaded executions and data races"))
|
||
other than the main thread ([[basic.start.main]](#basic.start.main "6.10.3.1 main function"))
|
||
or V and W have ordered initialization and
|
||
they are defined in the same translation unit,
|
||
the initialization of V is sequenced before
|
||
the initialization of W;
|
||
|
||
* [(3.1.2)](#basic.start.dynamic-3.1.2)
|
||
|
||
otherwise,
|
||
the initialization of V strongly happens before
|
||
the initialization of W[.](#basic.start.dynamic-3.1.sentence-1)
|
||
|
||
- [(3.2)](#basic.start.dynamic-3.2)
|
||
|
||
Otherwise, if the program starts a thread
|
||
other than the main thread
|
||
before either V or W is initialized,
|
||
it is unspecified in which threads
|
||
the initializations of V and W occur;
|
||
the initializations are unsequenced if they occur in the same thread[.](#basic.start.dynamic-3.2.sentence-1)
|
||
|
||
- [(3.3)](#basic.start.dynamic-3.3)
|
||
|
||
Otherwise, the initializations of V and W are indeterminately sequenced[.](#basic.start.dynamic-3.3.sentence-1)
|
||
|
||
[*Note [2](#basic.start.dynamic-note-2)*:
|
||
|
||
This definition permits initialization of a sequence of
|
||
ordered variables concurrently with another sequence[.](#basic.start.dynamic-3.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[4](#basic.start.dynamic-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7371)
|
||
|
||
A [*non-initialization odr-use*](#def:odr-use,non-initialization "6.10.3.3 Dynamic initialization of non-block variables [basic.start.dynamic]") is an odr-use ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3 One-definition rule")) not caused directly or indirectly by
|
||
the initialization of a non-block static or thread storage duration variable[.](#basic.start.dynamic-4.sentence-1)
|
||
|
||
[5](#basic.start.dynamic-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7377)
|
||
|
||
It is implementation-defined
|
||
whether the dynamic initialization of a
|
||
non-block non-inline variable with static storage duration
|
||
is sequenced before the first statement of main or is deferred[.](#basic.start.dynamic-5.sentence-1)
|
||
|
||
If it is deferred, it strongly happens before
|
||
any non-initialization odr-use
|
||
of any non-inline function or non-inline variable
|
||
defined in the same translation unit as the variable to be initialized[.](#basic.start.dynamic-5.sentence-2)[38](#footnote-38 "A non-block variable with static storage duration having initialization with side effects is initialized in this case, even if it is not itself odr-used ([term.odr.use], [basic.stc.static]).")
|
||
|
||
It is implementation-defined
|
||
in which threads and at which points in the program such deferred dynamic initialization occurs[.](#basic.start.dynamic-5.sentence-3)
|
||
|
||
*Recommended practice*: An implementation should choose such points in a way
|
||
that allows the programmer to avoid deadlocks[.](#basic.start.dynamic-5.sentence-4)
|
||
|
||
[*Example [1](#basic.start.dynamic-example-1)*: // - File 1 -#include "a.h"#include "b.h" B b;
|
||
A::A() { b.Use();}// - File 2 -#include "a.h" A a;
|
||
|
||
// - File 3 -#include "a.h"#include "b.h"extern A a;extern B b;
|
||
|
||
int main() { a.Use();
|
||
b.Use();}
|
||
|
||
It is implementation-defined
|
||
whether either a or b is
|
||
initialized before main is entered or whether the
|
||
initializations are delayed until a is first odr-used inmain[.](#basic.start.dynamic-5.sentence-5)
|
||
|
||
In particular, if a is initialized beforemain is entered, it is not guaranteed that b will be
|
||
initialized before it is odr-used by the initialization of a, that
|
||
is, before A::A is called[.](#basic.start.dynamic-5.sentence-6)
|
||
|
||
If, however, a is initialized
|
||
at some point after the first statement of main, b will
|
||
be initialized prior to its use in A::A[.](#basic.start.dynamic-5.sentence-7)
|
||
|
||
â *end example*]
|
||
|
||
[6](#basic.start.dynamic-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7437)
|
||
|
||
It is implementation-defined
|
||
whether the dynamic initialization of a
|
||
non-block inline variable with static storage duration
|
||
is sequenced before the first statement of main or is deferred[.](#basic.start.dynamic-6.sentence-1)
|
||
|
||
If it is deferred, it strongly happens before
|
||
any non-initialization odr-use
|
||
of that variable[.](#basic.start.dynamic-6.sentence-2)
|
||
|
||
It is implementation-defined
|
||
in which threads and at which points in the program such deferred dynamic initialization occurs[.](#basic.start.dynamic-6.sentence-3)
|
||
|
||
[7](#basic.start.dynamic-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7448)
|
||
|
||
It is implementation-defined
|
||
whether the dynamic initialization of a
|
||
non-block non-inline variable with thread storage duration
|
||
is sequenced before the first statement of the initial function of a thread or is deferred[.](#basic.start.dynamic-7.sentence-1)
|
||
|
||
If it is deferred,
|
||
the initialization associated with the entity for thread *t* is sequenced before the first non-initialization odr-use by *t* of any non-inline variable with thread storage duration
|
||
defined in the same translation unit as the variable to be initialized[.](#basic.start.dynamic-7.sentence-2)
|
||
|
||
It is implementation-defined
|
||
in which threads and at which points in the program such deferred dynamic initialization occurs[.](#basic.start.dynamic-7.sentence-3)
|
||
|
||
[8](#basic.start.dynamic-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7461)
|
||
|
||
If the initialization of
|
||
a non-block variable with static or thread storage duration
|
||
exits via an exception,
|
||
the function std::terminate is called ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#basic.start.dynamic-8.sentence-1)
|
||
|
||
[38)](#footnote-38)[38)](#footnoteref-38)
|
||
|
||
A non-block variable with static storage duration
|
||
having initialization
|
||
with side effects is initialized in this case,
|
||
even if it is not itself odr-used ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3 One-definition rule"), [[basic.stc.static]](basic.stc.static "6.8.6.2 Static storage duration"))[.](#footnote-38.sentence-1)
|
||
|
||
#### [6.10.3.4](#basic.start.term) Termination [[basic.start.term]](basic.start.term)
|
||
|
||
[1](#basic.start.term-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7470)
|
||
|
||
Constructed objects ([[dcl.init]](dcl.init "9.5 Initializers"))
|
||
with static storage duration are destroyed
|
||
and functions registered with std::atexit are called as part of a call tostd::exit ([[support.start.term]](support.start.term "17.5 Startup and termination"))[.](#basic.start.term-1.sentence-1)
|
||
|
||
The call to std::exit is sequenced before
|
||
the destructions and the registered functions[.](#basic.start.term-1.sentence-2)
|
||
|
||
[*Note [1](#basic.start.term-note-1)*:
|
||
|
||
Returning from main invokes std::exit ([[basic.start.main]](#basic.start.main "6.10.3.1 main function"))[.](#basic.start.term-1.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[2](#basic.start.term-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7487)
|
||
|
||
Constructed objects with thread storage duration within a given thread
|
||
are destroyed as a result of returning from the initial function of that thread and as a
|
||
result of that thread calling std::exit[.](#basic.start.term-2.sentence-1)
|
||
|
||
The destruction of all constructed objects with thread storage
|
||
duration within that thread strongly happens before destroying
|
||
any object with static storage duration[.](#basic.start.term-2.sentence-2)
|
||
|
||
[3](#basic.start.term-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7495)
|
||
|
||
If the completion of the constructor or dynamic initialization of an object with static
|
||
storage duration strongly happens before that of another, the completion of the destructor
|
||
of the second is sequenced before the initiation of the destructor of the first[.](#basic.start.term-3.sentence-1)
|
||
|
||
If the completion of the constructor or dynamic initialization of an object with thread
|
||
storage duration is sequenced before that of another, the completion of the destructor
|
||
of the second is sequenced before the initiation of the destructor of the first[.](#basic.start.term-3.sentence-2)
|
||
|
||
If an object is
|
||
initialized statically, the object is destroyed in the same order as if
|
||
the object was dynamically initialized[.](#basic.start.term-3.sentence-3)
|
||
|
||
For an object of array or class
|
||
type, all subobjects of that object are destroyed before any block
|
||
variable with static storage duration initialized during the construction
|
||
of the subobjects is destroyed[.](#basic.start.term-3.sentence-4)
|
||
|
||
If the destruction of an object with static or thread storage duration
|
||
exits via an exception,
|
||
the function std::terminate is called ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#basic.start.term-3.sentence-5)
|
||
|
||
[4](#basic.start.term-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7512)
|
||
|
||
If a function contains a block variable of static or thread storage duration that has been
|
||
destroyed and the function is called during the destruction of an object with static or
|
||
thread storage duration, the program has undefined behavior if the flow of control
|
||
passes through the definition of the previously destroyed block variable[.](#basic.start.term-4.sentence-1)
|
||
|
||
[*Note [2](#basic.start.term-note-2)*:
|
||
|
||
Likewise, the behavior is undefined
|
||
if the block variable is used indirectly (e.g., through a pointer)
|
||
after its destruction[.](#basic.start.term-4.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[5](#basic.start.term-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7523)
|
||
|
||
If the completion of the initialization of an object with static storage
|
||
duration strongly happens before a call to std::atexit (see[<cstdlib>](cstdlib.syn#header:%3ccstdlib%3e "17.2.2 Header <cstdlib> synopsis [cstdlib.syn]"), [[support.start.term]](support.start.term "17.5 Startup and termination")), the call to the function passed tostd::atexit is sequenced before the call to the destructor for the object[.](#basic.start.term-5.sentence-1)
|
||
|
||
If a
|
||
call to std::atexit strongly happens before the completion of the initialization of
|
||
an object with static storage duration, the call to the destructor for the
|
||
object is sequenced before the call to the function passed to std::atexit[.](#basic.start.term-5.sentence-2)
|
||
|
||
If a
|
||
call to std::atexit strongly happens before another call to std::atexit, the
|
||
call to the function passed to the second std::atexit call is sequenced before
|
||
the call to the function passed to the first std::atexit call[.](#basic.start.term-5.sentence-3)
|
||
|
||
[6](#basic.start.term-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7537)
|
||
|
||
If there is a use of a standard library object or function not permitted within signal
|
||
handlers ([[support.runtime]](support.runtime "17.14 Other runtime support")) that does not happen before ([[intro.multithread]](#intro.multithread "6.10.2 Multi-threaded executions and data races"))
|
||
completion of destruction of objects with static storage duration and execution ofstd::atexit registered functions ([[support.start.term]](support.start.term "17.5 Startup and termination")), the program has
|
||
undefined behavior[.](#basic.start.term-6.sentence-1)
|
||
|
||
[*Note [3](#basic.start.term-note-3)*:
|
||
|
||
If there is a use of an object with static storage
|
||
duration that does not happen before the object's destruction, the program has undefined
|
||
behavior[.](#basic.start.term-6.sentence-2)
|
||
|
||
Terminating every thread before a call to std::exit or the exit frommain is sufficient, but not necessary, to satisfy these requirements[.](#basic.start.term-6.sentence-3)
|
||
|
||
These
|
||
requirements permit thread managers as static-storage-duration objects[.](#basic.start.term-6.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[7](#basic.start.term-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7551)
|
||
|
||
Calling the function std::abort() declared in[<cstdlib>](cstdlib.syn#header:%3ccstdlib%3e "17.2.2 Header <cstdlib> synopsis [cstdlib.syn]") terminates the program without executing any destructors
|
||
and without calling
|
||
the functions passed to std::atexit() or std::at_quick_exit()[.](#basic.start.term-7.sentence-1)
|