Jens Maurer, [email protected]with other members of the transactional memory study group (SG5), including (in alphabetical order):
Hans Boehm, [email protected]
Justin Gottschlich, [email protected]
Victor Luchangco, [email protected]
Paul McKenney, [email protected]
Maged Michael, [email protected]
Mark Moir, [email protected]
Torvald Riegel, [email protected]
Michael Scott, [email protected]
Tatiana Shpeisman, [email protected]
Michael Spear, [email protected]
Michael Wong, [email protected] (chair of SG5)
This paper presents the current wording proposal (both core and library) for integrating transactional memory support into C++. For motivation and introductory overview, see the predecessor paper N3999 "Standard Wording for Transactional Memory Support for C++".
The companion paper N4180 motivates and explains the additional features that have been integrated since the Rapperswil meeting. Those were approved by EWG in Urbana.
transaction_safe
transaction_safe noinherit
for virtual
functions (non-viral)tx_exception
transaction_safe
on lambdas
transaction_safe noinherit
function overriding a transaction_safe
function is ill-formedmaybe transaction_safe
to transaction_safe noinherit
tx_exception
to trivially copyable
typestransaction_safe
, so there is a gap in the
specification if std::terminate ends up being called inside an atomic
transaction. The intersection of desirable and implementable semantics
for this case is still under discussion.std::function
inside
transactionsstd::exception
is the base of the exception
hierarchy. Should we declare its virtual what() function
transaction_safe
? [no; instead review definition of
derived classes such as length_error] This has serious ripple effects
to user code, in particular if that user code is totally unaware of
transactions. Telco 2014-08-11 and 2014-09-08: introduce "maybe
transaction_safe" for virtual functions, which is not viral, but
accepts undefined behavior.template<class T> class tx_exception : exception { ... };with a transaction-safe "what()" function and where "T" can be memcpy'd.
The start and the end of each synchronized block or atomic block is a full-expression (1.9 [intro.execution]). A synchronized block (6.x [stmt.sync]) or atomic block (6.x [stmt.tx]) that is not dynamically nested within another synchronized block or atomic block is called an outer block. [ Note: Due to syntactic constraints, blocks cannot overlap unless one is nested within the other. ] There is a global total order of execution for all outer blocks. If, in that total order, T1 is ordered before T2, then the end of T1 synchronizes with the start of T2.
Drafting notes: Together with 1.9p14, the first sentence ensures the appropriate (thread-local) sequencing. Inter-thread ordering is ensured by establishing a synchronizes-with relationship in the last sentence.
Change in 1.10 [intro.multithread] paragraph 10:Synchronized and atomic blocks as well as certainChange in 1.10 [intro.multithread] paragraph 21, and add a new paragraph following it:Certainlibrary calls synchronize with other synchronized blocks, atomic blocks, and library calls performed by another thread.
The execution of a program contains a data race if it
contains two conflicting actions in different threads, at least one of
which is not atomic, and neither happens before the other. Any such
data race results in undefined behavior. [ Note: It can be shown that
programs that correctly use mutexes, synchronized and atomic
blocks, 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 each value computation of an object being
taken from the last side effect on that object in that
interleaving. This is normally referred to as "sequential
consistency".
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. In fact, most single-threaded program transformations
continue to be allowed, since any program that behaves differently as
a result must perform an undefined operation. -- end note ]
[ Note: Due to the constraints on transaction safety (8.4.4 [dcl.fct.def.tx]), the following holds for a data-race-free program: If the start of an atomic block T is sequenced before an evaluation A, A is sequenced before the end of T, and A inter-thread happens before some evaluation B, then the end of T inter-thread happens before B. If an evaluation C inter-thread happens before that evaluation A, then C inter-thread happens before the start of T. These properties in turn imply that in any simple interleaved (sequentially consistent) execution, the operations of each atomic block appear to be contiguous in the interleaving. -- end note ]
In section 2.11 [lex.name] paragraph 2, add
transaction_safe
and
transaction_safe_noinherit
to the table.
In section 2.12 [lex.key], add the keywords
synchronized
, atomic_noexcept
,
atomic_cancel
, and atomic_commit
to
the table.
An lvalue of function type T can be converted to a prvalue of type "pointer toT."T". An lvalue of type "transaction-safe function" can be converted to a prvalue of type "pointer to function". The result is a pointer to the function. [ Footnote: ... ]
Drafting note: This ensures that overload resolution doesn't perceive dropping the "transaction-safe" as two conversions instead of just one. The same trick was applied for converting unscoped enumerations with fixed underlying type to the promoted underlying type (4.5p4).
Add a new section 4.14 [conv.tx]:4.14 [conv.tx] Transaction-safety conversion
A prvalue of type "pointer to
transaction_safe
function" can be converted to a prvalue of type "pointer to function". The result is a pointer to the function. A prvalue of type "pointer to member of typetransaction_safe
function" can be converted to a prvalue of type "pointer to member of type function". The result points to the member function.
[ Note: ... ] The composite pointer type of two operands p1 and p2 having types T1 and T2, respectively, where at least one is a pointer or pointer to member type orChange in 5.1.2 [expr.prim.lambda] paragraph 1:std::nullptr_t
, is:
- ...
- if T1 or T2 is "pointer to cv1 void" and the other type is "pointer to cv2 T", "pointer to cv12 void", where cv12 is the union of cv1 and cv2 ;
- if T1 is "pointer to
transaction_safe
function" and T2 is "pointer to function", where the function types are otherwise the same, T2, and vice versa;- ...
Change in 5.1.2 [expr.prim.lambda] paragraph 5:lambda-declarator: ( parameter-declaration-clause ) mutableopt transaction_safeopt exception-specificationopt attribute-specifier-seqopt trailing-return-typeopt
This function call operator or operator template is declaredChange in 5.1.2 [expr.prim.lambda] paragraph 6:const
(9.3.1) if and only if the lambda-expression's parameter-declaration-clause is not followed bymutable
. It is neither virtual nor declared volatile. It is declaredtransaction_safe
if and only if the lambda-expression's parameter-declaration-clause is followed bytransaction_safe
or, in a non-generic lambda-expression, it has a transaction-safe function definition (8.4.4 [dcl.fct.def.tx]). Any exception-specification specified on a lambda-expression applies to the corresponding function call operator or operator template. ...
The closure type for a non-generic lambda-expression with no
lambda-capture has a public non-virtual non-explicit const
transaction_safe
conversion function to
pointer to function with C++ language linkage (7.5 [dcl.link]) having
the same parameter and return types as the closure type's function
call operator. That pointer is a pointer to transaction-safe
function if the function call operator is transaction-safe.
Add at the end of 5.2.2 [expr.call] paragraph 1:
... [ Note: ... ] A call to a virtual function that is evaluated within a synchronized (6.x [stmt.sync]) or atomic block (6.x [stmt.tx]) results in undefined behavior if the virtual function is declaredAdd after 5.2.2 [expr.call] paragraph 9:transaction_safe_noinherit
and the final overrider is not declaredtransaction_safe
.
Recursive calls are permitted, except to the function named main (3.6.1)
Calling a function that is not transaction-safe (8.4.4 [dcl.fct.def.tx]) through a pointer to or lvalue of type "transaction-safe function" has undefined behavior.
Drafting note: This restriction might not be required if there is no defined way of obtaining a pointer to transaction-safe function from a pointer to (non-transaction-safe) function. One such way is precluded by the next change.
Change in 5.2.9 [expr.static.cast] paragraph 7:The inverse of any standard conversion sequence (Clause 4 [conv]) not containing an lvalue-to-rvalue (4.1 [conv.lval]), array-to-pointer (4.2 [conv.array]), function-to-pointer (4.3), null pointer (4.10), null member pointer (4.11),Change in 5.10 [expr.eq] paragraph 2:orboolean (4.12), or transaction-safety (4.14 [conv.tx]) conversion, can be performed explicitly usingstatic_cast
. ...
If at least one of the operands is a pointer, pointer conversions (4.10 [conv.ptr]), transaction-safety conversions (4.14 [conv.tx]), and qualification conversions (4.4 [conv.qual]) are performed on both operands to bring them to their composite pointer type (clause 5 [expr]). Comparing pointers is defined as follows: Before transaction-safety conversions, if one pointer is of type "pointer to function", the other is of type "pointer toChange in 5.16 [expr.con] paragraph 6:transaction_safe
function", and both point to the same function, it is unspecified whether the pointers compare equal. Otherwise,Twotwo pointers compare equal if they are both null, both point to the same function, or both represent the same address (3.9.2), otherwise they compare unequal.
- One or both of the second and third operands have pointer type; pointer conversions (4.10 [conv.ptr]), transaction-safety conversions (4.14 [conv.tx]), and qualification conversions (4.4 [conv.qual]) are performed to bring them to their composite pointer type (5 [expr]). ...
- ...
Add a new paragraph 3 at the end of 6.6 [stmt.jump]:statement: labeled-statement attribute-specifier-seqopt expression-statement attribute-specifier-seqopt compound-statement attribute-specifier-seqopt selection-statement attribute-specifier-seqopt iteration-statement attribute-specifier-seqopt jump-statement declaration-statement attribute-specifier-seqopt try-block synchronized-statement atomic-statement
Transfer out of an atomic block other than via an exception executes the end of the atomic block. [ Note: Colloquially, this is known as committing the transaction. For exceptions, see 15.2 [except.ctor]. -- end note ] Transfer out of a synchronized block (including via an exception) executes the end of the synchronized block.Add a new section 6.x [stmt.sync]:
6.x [stmt.sync] Synchronized statementAdd a new section 6.x [stmt.tx]:
synchronized-statement: synchronized compound-statementA synchronized statement is also called a synchronized block.
The start of the synchronized block is immediately before the opening
{
of the compound-statement. The end of the synchronized block is immediately after the closing}
of the compound-statement.A
goto
orswitch
statement shall not be used to transfer control into a synchronized block.[ Example:
int f() { static int i = 0; synchronized { printf("before %d\n", i); ++i; printf("after %d\n", i); return i; } }Each invocation off
(even when called from several threads simultaneously) retrieves a unique value (ignoring overflow). The output is guaranteed to comprise consistent before/after pairs. -- end example ]
6.x [stmt.tx] Atomic statement
atomic-statement: atomic_noexcept compound-statement atomic_cancel compound-statement atomic_commit compound-statementAn atomic statement is also called an atomic block. The program is ill-formed if the compound-statement is a transaction-unsafe statement (8.4.4 [dcl.fct.def.tx]).
The start of the atomic block is immediately before the opening
{
of the compound-statement. The end of the atomic block is immediately after the closing}
of the compound-statement. [ Note: Thus, variables with automatic storage duration declared in the compound-statement are destroyed prior to reaching the end of the atomic block; see 6.6 [stmt.jump]. -- end note ]A
goto
orswitch
statement shall not be used to transfer control into an atomic block.[ Example:
int f() { static int i = 0; atomic_noexcept { ++i; return i; } }Each invocation off
(even when called from several threads simultaneously) retrieves a unique value (ignoring overflow). -- end example ]
... The asm declaration is conditionally-supported; its meaning is implementation-defined. [ Note: Typically it is used to pass information through the implementation to an assembler. -- end note ] It is implementation-defined which asm declarations are transaction-safe (8.4.4 [dcl.fct.def.tx]), if any.Add a new section 7.6.6 [dcl.attr.sync]:
7.6.6 [dcl.attr.sync] Attribute for optimization in synchronized blocksThe attribute-token
optimize_for_synchronized
specifies that a function definition should be optimized for invocation from a synchronized-statement (6.x [stmt.sync]). It shall appear at most once in each attribute-list and no attribute-argument-clause shall be present. The attribute may be applied to the declarator-id in a function declaration. The first declaration of a function shall specify theoptimize_for_synchronized
attribute if any declaration of that function specifies theoptimize_for_synchronized
attribute. If a function is declared with theoptimize_for_synchronized
attribute in one translation unit and the same function is declared without theoptimize_for_synchronized
attribute in another translation unit, the program is ill-formed; no diagnostic required.[ Example:
// translation unit 1 [[optimize_for_synchronized]] int f(int); void g(int x) { synchronized { int ret = f(x*x); } } // translation unit 2 #include <iostream> extern int verbose; [[optimize_for_synchronized]] int f(int x) { if (x >= 0) return x; if (verbose > 1) std::cerr << "failure: negative x" << std::endl; return -1; }If the attribute were not present forf
, which is not declaredtransaction_safe
, a program might have to drop out of speculative execution ing
's synchronized block every time when callingf
, although that is only actually required for displaying the error message in the rare verbose error case. -- end example ]
Change in 8.3.5 [dcl.fct] paragraphs 1 and 2:parameters-and-qualifiers: ( parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt tx-qualifieropt exception-specificationopt attribute-specifier-seqopt tx-qualifier: transaction_safe transaction_safe_noinherit
In a declaration T D where D has the formChange in 8.3.5 [dcl.fct] paragraph 5:D1 ( parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt tx-qualifieropt exception-specificationopt attribute-specifier-seqoptand the type of the contained declarator-id in the declaration T D1 is "derived-declarator-type-list T", the type of the declarator-id in D is "derived-declarator-type-listtransaction_safe
opt function of (parameter-declaration-clause) cv-qualifier-seqopt ref-qualifieropt returning T", where the optionaltransaction_safe
is present if a tx-qualifier is present. The optional attribute-specifier-seq appertains to the function type.In a declaration T D where D has the form
D1 ( parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt tx-qualifieropt exception-specificationopt attribute-specifier-seqopt trailing-return-typeand the type of the contained declarator-id in the declaration T D1 is "derived-declarator-type-list T", T shall be the single type-specifier auto. The type of the declarator-id in D is "derived-declarator-type-listtransaction_safe
opt function of (parameter-declaration-clause) cv-qualifier-seqopt ref-qualifieropt returning trailing-return-type", where the optionaltransaction_safe
is present if a tx-qualifier is present. The optional attribute-specifier-seq appertains to the function type.
... After determining the type of each parameter, any parameter of type "array of T" or "Change in 8.3.5 [dcl.fct] paragraph 6:transaction_safe
opt function returning T" is adjusted to be "pointer to T" or "pointer totransaction_safe
opt function returning T," respectively. ...
... The return type, the parameter-type-list, the ref-qualifier,Add at the end of section 8.3.5 [dcl.fct]:andthe cv-qualifier-seq, and thetransaction_safe
qualifier, but not the default arguments (8.3.6 [dcl.fct.default]) or the exception specification (15.4 [except.spec]), are part of the function type. ...
Change in section 8.4.1 [dcl.fct.def.general] paragraph 2:The
transaction_safe_noinherit
qualifier may only appear in a function declarator that declares a virtual function in a class definition. A virtual function declared with thetransaction_safe_noinherit
qualifier is considered to be declaredtransaction_safe
. [ Note: A virtual function so declared can be overridden by a function that is not transaction-safe (see 10.3 class virtual), but calling such an overrider from a synchronized or atomic block causes undefined behavior (see 5.2.2 expr.call). -- end note ] All declarations of a function shall be declaredtransaction_safe
if any declaration of that function is declaredtransaction_safe
, except that the declaration of an explicit specialization (14.7.3 [temp.expl.spec]) may differ from the declaration that would be instantiated from the template; no diagnostic is required if conflicting declarations appear in different translation units.
The declarator in a function-definition shall have the formD1( parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt exception-specificationopt attribute-specifier-seqoptparameters-and-qualifiers trailing-return-typeopt
[ Drafting note: This is intended to reduce the grammar redundancies around function declarators. ]
Add a section after 8.4.3 [dcl.fct.def.delete]:8.4.4 [dcl.fct.def.tx] Transaction-safe function definitions[ Drafting note: This wording is intended to recurse through the "statement" grammar, but not inside expressions. In particular, the compound-statement of a lambda determines the transaction-safety of the lambda's operator() function, but, unless called, does not influence the transaction-safety of the surrounding context. ]
An expression is transaction-unsafe if it contains any of the following as a potentially-evaluated subexpression (3.2 [basic.def.odr]):
- an lvalue-to-rvalue conversion (4.1 [conv.lval]) applied to a volatile glvalue [ Note: referring to a volatile object through a non-volatile glvalue has undefined behavior; see 7.1.6.1 [dcl.type.cv] -- end note ],
- an expression that modifies an object through a volatile glvalue,
- the creation of a temporary object of volatile-qualified type or with a subobject of volatile-qualified type,
- a function call (5.2.2 expr.call) whose postfix-expression is an id-expression that names a non-virtual function that is not transaction-safe,
- an implicit call of a non-virtual function that is not transaction-safe, or
- any other call of a function, where the function type is not "
transaction_safe
function".A statement is a transaction-unsafe statement if it lexically directly contains one of the following (including evaluations of default argument expressions in function calls and evaluations of brace-or-equal-initializers for non-static data members in aggregate initialization (8.5.1 dcl.init.aggr), but ignoring the declaration of default argument expressions, local classes, and the compound-statement of a lambda-expression):
- a full-expression that is transaction-unsafe,
- an asm-definition (7.4 [dcl.asm]) that is not transaction-safe,
- a declaration of a variable of volatile-qualified type or with a subobject of volatile-qualified type, or
- a statement that is transaction-unsafe (recursively).
A function has a transaction-safe definition if none of the following applies:Drafting note: Implicitly-defined special member functions and lambda expressions should be automatically covered by the wording above.[ Example:
- any parameter has volatile-qualified type or has a subobject of volatile-qualified type,
- its compound-statement (including the one in the function-try-block, if any) is a transaction-unsafe statement,
- for a constructor or destructor, the corresponding class has a volatile non-static data member, or
- for a constructor, a full-expression in a mem-initializer or an assignment-expression in a brace-or-equal-initializer that is not ignored (12.6.2 [class.base.init]) is transaction-unsafe.
extern volatile int * p = 0; struct S { virtual ~S(); }; int f() transaction_safe { int x = 0; // ok: not volatile p = &x; // ok: the pointer is not volatile int i = *p; // error: read through volatile glvalue S s; // error: invocation of unsafe destructor }-- end example ]A function declared
transaction_safe
shall have a transaction-safe definition.A function is transaction-safe if it is declared
transaction_safe
(see 8.3.5 [dcl.fct]), or if it is a non-virtual function defined before its first odr-use (3.2 [basic.def.odr]) and it has a transaction-safe function definition. A specialization of a function template or of a member function of a class template, where the function or function template is not declaredtransaction_safe
, but defined before the first point of instantiation, is transaction-safe if and only if it satisfies the conditions for a transaction-safe function definition. [ Note: Even if a function is implicitly transaction-safe, its function type is not changed to "transaction_safe
function". -- end note ]While determining whether a function
f
is transaction-safe,f
is assumed to be transaction-safe for directly and indirectly recursive calls. [ Example:int f(int x) { // is transaction-safe if (x <= 0) return 0; return x + f(x-1); }-- end example ]
A function that overrides a function declaredtransaction_safe
, but nottransaction_safe_noinherit
, is implicitly considered to be declaredtransaction_safe
. [ Note: Its definition is ill-formed unless it actually has a transaction-safe definition (8.4.4 dcl.fct.def.tx). -- end note ] A function declaredtransaction_safe_noinherit
that overrides a function declaredtransaction_safe
(but nottransaction_safe_noinherit
) is ill-formed. [ Example:struct B { virtual void f() transaction_safe; virtual ~B() transaction_safe_noinherit; }; // pre-existing code struct D1 : B { void f() override { } // ok ~D1() override { } // ok }; struct D2 : B { void f() override { std::cout << "D2::f" << std::endl; } // error: transaction-safe f has transaction-unsafe definition ~D2() override { std::cout << "~D2" << std::endl; } // ok }; struct D3 : B { void f() transaction_safe_noinherit override; // error: B::f() is transaction_safe }; int main() { D2 * d2 = new D2; B * b2 = d2; atomic_commit { B b; // ok D1 d1; // ok B& b1 = d1; D2 x; // error: destructor of D2 is not transaction-safe b1.f(); // ok, calls D1::f() delete b2; // undefined behavior: calls unsafe destructor of D2 } }-- end example ]
Certain function declarations cannot be overloaded:In 13.3.3.1.1 [over.ics.scs], add an entry to table 12:
- Function declarations that differ only in the return type cannot be overloaded.
- Function declarations that differ only in the presence or absence of a tx-qualifier cannot be overloaded.
- ...
Change in 13.4 [over.over] paragraph 1:
- Conversion: Transaction-safety conversion
- Category: Lvalue transformation
- Rank: Exact Match
- Subclause: 4.14 [conv.tx]
...Change in 13.4 [over.over] paragraph 7:The function selected is the one whose type is identical to the function type of the target type required in the context.A function with typeF
is selected for the function typeFT
of the target type required in the context if F (after possibly applying the transaction-safety conversion (4.14 [conv.tx])) is identical to FT. [ Note: ... ]
[ Note:There are no standard conversions (Clause 4) of one pointer-to-function type into another. In particular, evenEven if B is a public base of D, we haveD* f(); B* (*p1)() = &f; // error void g(D*); void (*p2)(B*) = &g; // error]
A non-type template-parameter of type "array of T" or "Add a new paragraph in 14.7.3 temp.expl.spec paragraph 12:transaction_safe
opt function returning T" is adjusted to be of type "pointer to T" or "pointer totransaction_safe
opt function returning T", respectively. [ Example: ... ]
An explicit specialization of a function template or of a member function of a class template can be declaredAdd a new paragraph at the end of 14.8 [temp.fct.spec]:transaction_safe
(8.3.5 [dcl.fct.def]) independently of whether the corresponding template entity is declaredtransaction_safe
. [ Example:template<class T> void f(T) transaction_safe; template<> void f(bool); // not transaction-safe-- end example ]
A specialization instantiated from a function template or from
a member function of a class template, where the function template or
member function is declared transaction_safe
,
shall have a transaction-safe definition (8.4.4 [dcl.fct.def.tx]).
Change in 14.8.2.1 temp.deduct.call paragraph 4:
... However, there are three cases that allow a difference:
- ...
- The transformed A can be another pointer or pointer to member type that can be converted to the deduced A via a qualification conversion (4.4 c[onv.qual]) or a transaction-safety conversion (4.14 [conv.tx]).
- ...
... Evaluating a throw-expression with an operand throws an exception; the type of the exception object is determined by removing any top-level cv-qualifiers from the static type of the operand and adjusting the type from "array of T" or "Change the section heading of 15.2 [except.ctor] and paragraph 1:transaction_safe
opt function returning T" to "pointer to T" or "pointer totransaction_safe
opt function returning T," respectively.
Section 15.2 [except.ctor] Constructors,In section 15.2 [except.ctor], add new paragraphs 4 and 5:anddestructors, and atomic blocksAs control passes from the point where an exception is thrown to a handler, destructors are invoked for all automatic objects constructed since the try block was entered yet still in scope (6.6 [stmt.jump], and atomic blocks are terminated (see below) where the start, but not the end of the block, was executed since the try block was entered (6.x [stmt.tx]). The automatic objects are destroyed and atomic blocks are terminated in the reverse order of the completion of their construction and the execution of the start of the atomic blocks.
An atomic block is terminated according to its kind, as follows: Terminating anChange in 15.3 except.handle paragraph 3:atomic_commit
block executes the end of the atomic block (1.10 intro.multithread) and has no further effect. [ Note: That is, control exits the atomic block after causing inter-thread synchronization. -- end note ] Terminating anatomic_cancel
block, if the type of the current exception does not support transaction cancellation, or terminating anatomic_noexcept
block, invokesstd::abort
(18.5 [support.start.term]). [ Footnote: If the effects of the atomic block become visible to other threads prior to program termination, some thread might make progress based on broken state, making debugging harder. -- end footnote ]. Terminating anatomic_cancel
block, if the type of the current exception supports transaction cancellation, cancels the atomic block by performing the following steps, in order:
- A temporary object is copy-initialized (8.5 [dcl.init]) from the exception object. [ Note: if the initialization terminates via an exception,
std::terminate
is called (15.1 [except.throw]). -- end note ]- The values of all memory locations in the program that were modified by side effects of the operations of the atomic block, except those occupied by the temporary object, are restored to the values they had at the time the start of the atomic block was executed.
- The end of the atomic block is executed. [ Note: This causes inter-thread synchronization. -- end note ]
- The temporary object is used as the exception object in the subsequent stack unwinding.
[ Note: A cancelled atomic block, although having no visible effect, still participates in data races (1.10 [intro.multithread]). -- end note ]
Non-volatile scalar types support transaction cancellation, as do those types specified as doing so in clauses 18 and 19.
A handler is a match for an exception object of type E ifChange in 15.4 except.spec paragraph 2:
- ...
- the handler is of type cv T or const T& where T is a pointer type and E is a pointer type that can be converted to T by
either or both ofone or more of
- a standard pointer conversion (4.10 [conv.ptr]) not involving conversions to pointers to private or protected or ambiguous classes
- a qualification conversion (4.4 [conv.qual])
- a transaction-safety conversion (4.14 [conv.tx])
- ...
... A type cv T, "array of T", or "transaction_safe
opt function returning T" denoted in an exception-specification is adjusted to type T, "pointer to T", or "pointer totransaction_safe
opt function returning T", respectively.
Drafting note: The following guidelines were employed for
transaction-safety requirements in the standard library, roughly
oriented on the guidelines for constexpr
and
noexcept
:
transaction_safe
. Functions declared
noexcept
strongly hint in that direction. Example:
size()
member function of containers.In table 27 in 17.6.3.5 [allocator.requirements] paragraph 2, add a note for
- ...
- Synchronization: the synchronization operations (1.10) applicable to the function
- Transactions: the transaction-related properties of the function, in particular whether the function is transaction-safe (8.4.4 [dcl.fct.def.tx])
- ...
X::rebind
:
All operations that are transaction-safe onAdd a new section in 17.6.5 [conforming]:X
shall be transaction-safe onY
.
17.6.5.16 [lib.txsafe] Transaction safetyChange in 18.5 [support.start.term] paragraph 4:This standard explicitly requires that certain standard library functions are transaction-safe (8.4.4 dcl.fct.def.tx). An implementation shall not declare any standard library function signature as
transaction_safe
except for those where it is explicitly required.
Add to 18.6.1 [new.delete] paragraph 1:[[noreturn]] void abort(void) transaction_safe noexcept ;The functionabort()
has additional behavior in this International Standard:
- The program is terminated without executing destructors for objects of automatic, thread, or static storage duration and without calling functions passed to
atexit
() (3.6.3).
... The library versions of the global allocation and
deallocation functions are declared transaction_safe
(8.3.5 dcl.fct).
Add a first paragraph to section 18.6.2 [alloc.errors]:
The classesbad_alloc
,bad_array_length
, andbad_array_new_length
support transaction cancellation (15.2 [except.ctor]). [ Note: Special support from the implementation might be necessary to successfully rethrow such an exception after leaving an atomic_cancel block. -- end note ]
In 18.6.2.1 [bad.alloc] and 18.6.2.2 [new.badlength], add
transaction_safe
to the declaration of each non-virtual
member function and add
transaction_safe_noinherit
to the
declaration of each virtual member function.
The class bad_cast
defines the type of objects thrown as
exceptions by the implementation to report the execution of an invalid
dynamic-cast expression (5.2.7 [expr.dynamic.cast]). The class
supports transaction cancellation (15.2 [except.ctor]). [
Note: Special support from the implementation might be necessary to
successfully rethrow such an exception after leaving an atomic_cancel
block. -- end note ]
In 18.7.2 [bad.cast], add transaction_safe
to the
declaration of each non-virtual member function and add
transaction_safe_noinherit
to the declaration of each virtual
member function.
The class bad_typeid
defines the type of objects thrown
as exceptions by the implementation to report a null pointer in a
typeid expression (5.2.8 [expr.typeid]). The class supports
transaction cancellation (15.2 [except.ctor]). [ Note: Special
support from the implementation might be necessary to successfully
rethrow such an exception after leaving an atomic_cancel block. -- end
note ]
In 18.7.3 [bad.typeid], add transaction_safe
to the
declaration of each non-virtual member function and add
transaction_safe_noinherit
to the
declaration of each virtual member function.
In 18.8.1 [exception] and 18.8.2 [bad.exception], add
transaction_safe
to the declaration of each non-virtual
member function and add
transaction_safe_noinherit
to the
declaration of each virtual member function.
The classChange in 18.10 [support.runtime] paragraph 4:bad_exception
defines the type of objects thrown as described in(15.5.2 [except.unexpected]).15.5.2 [except.unexpected]. The class supports transaction cancellation (15.2 [except.ctor]). [ Note: Special support from the implementation might be necessary to successfully rethrow such an exception after leaving an atomic_cancel block. -- end note ]
The function signatureChange in 19.2 [std.exceptions] paragraph 3:longjmp(jmp_buf jbuf, int val)
has more restricted behavior in this International Standard. Asetjmp
/longjmp
call pair has undefined behavior if replacing thesetjmp
andlongjmp
bycatch
andthrow
would invoke any non-trivial destructors for any automatic objects, or would transfer out of a synchronized block (6.x [stmt.sync]) or atomic block (6.x [stmt.tx]).
... These exceptions are related by inheritance. The exception classes support transaction cancellation (15.2 [except.ctor]). [ Note: Special support from the implementation might be necessary to successfully rethrow such an exception after leaving an atomic_cancel block. -- end note ].Add the following to the synopsis in 19.2 [std.exceptions] paragraph 3:
template<class T> class tx_exception;
In 19.2 [std.exceptions], add transaction_safe
to the
declaration of each non-virtual member function and add
transaction_safe_noinherit
to the
declaration of each virtual member function.
Class templatetx_exception
namespace std { template<class T> class tx_exception : public runtime_error { public: explicit tx_exception(T value) transaction_safe; tx_exception(T value, const char* what_arg) transaction_safe; tx_exception(T value, const string& what_arg) transaction_safe; T get() const transaction_safe; }; }A specialization oftx_exception
supports transaction cancellation (15.2 [except.ctor]). IfT
is not a trivially copyable type (3.9 [basic.types]), the program is ill-formed.tx_exception(T value) transaction_safe;Effects: Constructs an object of class
tx_exception
.Postcondition: The result of calling
get()
is equivalent tovalue
.tx_exception(T value, const char * what_arg) transaction_safe;Effects: Constructs an object of class
tx_exception
.Postcondition:
strcmp(what(), what_arg) == 0
and the result of callingget()
is equivalent tovalue
.tx_exception(T value, const string& what_arg) transaction_safe;Effects: Constructs an object of class
tx_exception
.Postcondition:
strcmp(what(), what_arg.c_str()) == 0
and the result of callingget()
is equivalent tovalue
.
Change in 20.7.3.2 [pointer.traits.functions]:
Change the signature in 20.7.5 [ptr.align] paragraph 1:static pointer pointer_traits::pointer_to(see below r); static pointer pointer_traits<T*>::pointer_to(see below r) transaction_safe noexcept;...
Transactions: The first member function is transaction-safe if the invoked member function ofPtr
is transaction-safe.
In 20.7.8.2 [allocator.traits.members], add before paragraph 1:void* align(std::size_t alignment, std::size_t size, void*& ptr, std::size_t& space) transaction_safe;
A function in this section is transaction-safe if the invoked function (as specified below) is transaction-safe.
In 20.7.9.1 [allocator.members], add "transaction_safe
"
to the declarations of the following member functions:
address
(twice), allocate
,
deallocate
, max_size
.
Change the signatures in 20.7.11 [temporary.buffer]:
template <class U, class... Args> void construct(U* p, Args&&... args);Effects:::new((void *)p) U(std::forward
(args)...)
Transactions: Transaction-safe if the invoked constructor of U is transaction-safe.
template <class U> void destroy(U* p);Effects:p->~U()
Transactions: Transaction-safe if the destructor of U is transaction-safe.
Change in 20.7.12 [specialized.algorithms] paragraph 1:template <class T> pair<T*, ptrdiff_t> get_temporary_buffer(ptrdiff_t n) transaction_safe noexcept;...template <class T> void return_temporary_buffer(T* p) transaction_safe;
... In the following algorithms, if an exception is thrown there are no effects. Each of the following functions is transaction-safe if the constructor invoked via the placement allocation function is transaction-safe.Change the signature in 20.7.12.1 [specialized.addressof]:
Add after 20.7.13 [c.malloc] paragraph 2:template <class T> T* addressof(T& r) transaction_safe noexcept;
[ Drafting note: This covers calloc, malloc, free, and realloc.]The contents are the same as the Standard C library header <stdlib.h>, with the following changes:
The functions are transaction-safe.
Change in 20.7.13 [c.malloc] paragraph 7:
The contents are the same as the Standard C library header
<string.h>, with the change to memchr()
specified in
21.8 [c.strings]. The functions are transaction-safe.
[ Drafting note: This covers memchr, memcmp, memcpy, memmove, and memset. ]
Change in 20.8.1 [unique.ptr] paragraph 5:... The template parameter T of unique_ptr may be an incomplete type. Each of the functions in this section is transaction-safe if either no functions are called or all functions called are transaction-safe.Add after 21.1 [strings.general] paragraph 1:
All functions in this Clause are transaction-safe if the required operations on the supplied allocator (17.6.3.5 [allocator.requirements]) and character traits (21.2.1 [char.traits.require]) are transaction-safe.
In 21.4.3 [string.iterators], 21.4.4 [string.capacity], 21.4.5
[string.access], add "transaction_safe
" to the
declarations of all member functions.
Unless unconditionally specified to be transaction-safe, a function in this Clause is transaction-safe if all required operations are transaction-safe. [ Note: This includes operations on the element type, onIn table 96 in 23.2.1 [container.requirements.general] paragraph 4, add a note forstd::allocator_traits
, and onCompare
,Pred
, orHash
objects, depending on the respective function. -- end note ]
X::iterator
and
X::const_iterator
:
all functions required for the iterator category are transaction-safeAdd in 23.2.1 [container.requirements.general] after paragraph 6:
Add in 23.2.1 [container.requirements.general] after paragraph 10:... If the container is empty, then
The member functionsbegin() == end()
.begin
,end
,cbegin
,cend
,size
,max_size
, andempty
are transaction-safe.
Add in 23.2.3 [sequence.reqmts] before paragraph 17:If the iterator type of a container belongs to the bidirectional or random access iterator categories (24.2 [iterator.requirements]), the container is called reversible and satisfies the additional requirements in Table 97.
[ table ]
The member functionsrbegin
,rend
,crbegin
, andcrend
are transaction-safe.
Add in 23.2.5 [unord.req] after paragraph 12:[ table ]
The member functionsfront
,back
, andat
as well as the indexing operationa[n]
are transaction-safe.The member function
at()
provides bounds-checked access to container elements.at()
throwsout_of_range
ifn >= a.size()
.
The behavior of a program that uses operator== or operator!= on unordered containers is undefined unless the Hash and Pred function objects respectively have the same behavior for both containers and the equality comparison operator for Key is a refinement [ Footnote: ... ] of the partition into equivalent-key groups produced by Pred.
The member functionsIn 23.3.2.1 [array.overview] and the corresponding subsections, add "bucket_count
,max_bucket_count
,bucket_size
,begin
,end
,cbegin
,cend
,load_factor
, andmax_load_factor
are transaction-safe.
transaction_safe
" to the declarations of all member
functions except fill
and swap
.
In 23.3.3.1 [deque.overview], add
"transaction_safe
" to the declarations of all variants of
the begin
and end
member functions and to
the declarations of size
, max_size
,
empty
, operator[]
, front
,
back
.
In 23.3.4.1 [forwardlist.overview] and 23.3.4.6
[forwardlist.ops], add "transaction_safe
" to the
declarations of all variants of the begin
and
end
member functions and to the declarations of
max_size
, empty
, front
,
splice_after
, and reverse
.
transaction_safe
" to the declarations of all variants of
the begin
and end
member functions and to
the declarations of size
, max_size
,
empty
, front
, back
,
splice
, and reverse
.
In 23.3.6.1 [vector.overview], 23.3.6.3 [vector.capacity], and
23.3.6.4 [vector.data], add "transaction_safe
" to the
declarations of all variants of the begin
and
end
member functions and to the declarations of
size
, max_size
, capacity
,
empty
, operator[]
, front
,
back
, data
.
In 23.3.7 [vector.bool], add "transaction_safe
"
to the declarations of all variants of the begin
and
end
member functions, to the declarations of
size
, max_size
, capacity
,
empty
, operator[]
, front
,
back
, and flip
, and to the static member
function swap
.
In 23.4.4.1 [map.overview], add
"transaction_safe
" to the declarations of all variants of
the begin
and end
member functions and to
the declarations of size
, max_size
, and
empty
.
In 23.4.5.1 [multimap.overview], add
"transaction_safe
" to the declarations of all variants of
the begin
and end
member functions and to
the declarations of size
, max_size
, and
empty
.
In 23.4.6.1 [set.overview], add
"transaction_safe
" to the declarations of all variants of
the begin
and end
member functions and to
the declarations of size
, max_size
, and
empty
.
In 23.4.7.1 [multiset.overview], add "transaction_safe
"
to the declarations of all variants of the begin
and
end
member functions and to the declarations of
size
, max_size
, and
empty
.
In 23.5.4.1 [unord.map.overview], add
"transaction_safe
" to the declarations of all variants of
the begin
and end
member functions and to
the declarations of size
, max_size
,
empty
, operator[]
,
bucket_count
, max_bucket_count
,
bucket_size
, load_factor
, and
max_load_factor
.
In 23.5.5.1 [unord.multimap.overview], add
"transaction_safe
" to the declarations of all variants of
the begin
and end
member functions and to
the declarations of size
, max_size
,
empty
, operator[]
,
bucket_count
, max_bucket_count
,
bucket_size
, load_factor
, and
max_load_factor
.
In 23.5.6.1 [unord.set.overview], add
"transaction_safe
" to the declarations of all variants of
the begin
and end
member functions and to
the declarations of size
, max_size
,
empty
, operator[]
,
bucket_count
, max_bucket_count
,
bucket_size
, load_factor
, and
max_load_factor
.
In 23.5.7.1 [unord.multiset.overview], add
"transaction_safe
" to the declarations of all variants of
the begin
and end
member functions and to
the declarations of size
, max_size
,
empty
, operator[]
,
bucket_count
, max_bucket_count
,
bucket_size
, load_factor
, and
max_load_factor
.
Add in 23.6.1 [container.adaptors.general] after paragraph 3:
For container adaptors, noChange in 24.4.4 [iterator.operations] paragraph 1:swap
function throws an exception unless that exception is thrown by the swap of the adaptor'sContainer
orCompare
object (if any).A member function
f
of a container adaptor is transaction-safe if the required member functions of the adaptor'sContainer
andCompare
(if any) are transaction-safe, as given by the specification forf
.
Since only random access iterators provide + and - operators, the library provides two function templates advance and distance. These function templates use + and - for random access iterators (and are, therefore, constant time for them); for input, forward and bidirectional iterators they use ++ to provide linear time implementations. A specialization of a function template specified in this Clause is transaction-safe if all operations required for the template arguments are transaction-safe.Change in 24.5.1 [reverse.iterators] paragraph 1:
Class templateAdd a new paragraph after 24.5.2 [insert.iterators] paragraph 2:reverse_iterator
is an iterator adaptor that iterates from the end of the sequence defined by its underlying iterator to the beginning of that sequence. The fundamental relation between a reverse iterator and its corresponding iterator i is established by the identity:&*(reverse_iterator(i)) == &*(i - 1)
. A member function specified in this Clause is transaction-safe if all operations required for the template argument ofreverse_iterator
are transaction-safe.
A function or function template specified in this Clause is transaction-safe if all operations required for the template arguments are transaction-safe.Add a new paragraph after 24.5.3 [move.iterators] paragraph 2:
A member function specified in this Clause is transaction-safe if all operations required for the template arguments are transaction-safe.Change in 24.7 [iterator.range] paragraph 1:
In addition to being available ..., and
<vector>
. A specialization of a function template
specified in this Clause is transaction-safe if all required
operations (as specified by the Returns element) are
transaction-safe.
In 24.7 [iterator.range], add "transaction_safe
"
to the declarations of begin(T (&array)[N])
and
end(T (&array)[N])
Add a new 25.1 [algorithms.general] paragraph 13:
A specialization of a function template specified in this Clause is transaction-safe if all functions and operations required for the template arguments are transaction-safe. [ Example: TheAdd a new paragraph after 26.7.1 [numeric.ops.overview] paragraph 1:fill
function (25.3.6 [alg.fill]) is transaction-safe if all required operations of itsForwardIterator
template argument are transaction-safe and ifT
's copy assignment operator is transaction-safe. -- end example ]
A specialization of a function template specified in this Clause is transaction-safe if all functions and operations required for the template arguments are transaction-safe (see 25.1 [algorithms.general]).Add after 26.8 [c.math] paragraph 4:
The contents of these headers are the same as the Standard C library headers <math.h> and <stdlib.h> respectively, with the following changes:The functions from <stdlib.h>, including the additional overloads in <cstdlib> (see below), but excluding rand and srand, are transaction-safe.
[ Drafting note: This covers abs, ldiv, rand, div,
llabs, srand, labs, and lldiv.]