ISO/IEC JTC1 SC22 WG21 P2066R7
Authors: Hans Boehm, Victor Luchangco, Jens Maurer, Michael L. Scott, Michael Spear, and Michael Wong
Reply to: Jens Maurer <Jens.Maurer@gmx.net>
Target audience: EWG, LEWG
2021-05-14

P2066R7: Suggested draft TS for C++ Extensions for Minimal Transactional Memory

Introduction

This paper presents suggested wording for a future Technical Specification on a variant of Transactional Memory. See P1875R2 "Transactional Memory Lite Support in C++" for discussion.

Paper history

Changes in R1 since R0

Changes in R2 since R1

Changes in R3 since R2

Changes in R4 since R3

Changes in R5 since R4

Changes in R6 since R5

Changes in R7 since R6

Questions for TS deployment

Wording changes

These wording changes are relative to the current C++ Working Draft, N4849.

In 5.10 [lex.name], add atomic to table 4 [tab:lex.name.special].

Change in 6.9.1 [intro.execution] paragraph 5:

A full-expression is
Change in 6.9.2.1 [intro.races] paragraph 6:
Atomic blocks as well as Certain certain library calls may synchronize with other atomic blocks and library calls performed by another thread.
Add a new paragraph after 6.9.2.1 [intro.races] paragraph 20:
An atomic block that is not dynamically nested within another atomic block is termed a transaction. [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 transactions. If, in that total order, a transaction T1 is ordered before a transaction T2, then [ Note: If the evaluations in T1 and T2 do not conflict, they might be executed concurrently. -- end note ]
Two actions are potentially concurrent if ...
Change in 6.9.2.1 [intro.races] paragraph 21:
... [Note: It can be shown that programs that correctly use mutexes, 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". ...
Add a new paragraph after 6.9.2.1 [intro.races] paragraph 21:
[ Note: 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, A strongly happens before some evaluation B, and B is not sequenced before the end of T, then the end of T strongly happens before B. If an evaluation C strongly happens before that evaluation A and C is not sequenced after the start of T, then C strongly 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 ]
Change in 6.9.2.2 [intro.progress] paragraph 1:
The implementation may assume that any thread will eventually do An inter-thread side effect is one of the following: The implementation may assume that any thread will eventually terminate or evaluate an inter-thread side effect. [Note: This is intended to allow compiler transformations such as removal of empty loops, even when termination cannot be proven. — end note]
Add a production to the grammar in 8.1 [expr.pre]:
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
      atomic-statement
Add a new subclause before 8.8 [stmt.dcl]:
8.8 Atomic statement [stmt.tx]

atomic-statement:
     atomic do compound-statement
An atomic-statement is also called an atomic block.

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 8.7 [stmt.jump]. -- end note ]

A goto or switch statement shall not be used to transfer control into an atomic block.

If the execution of an atomic block evaluates an inter-thread side effect (6.9.2.2 [intro.progress]) or if an atomic block is exited via an exception, the behavior is undefined.

Recommended practice: In case an atomic block is exited via an exception, the program should be terminated without invoking a terminate handler (17.9.5 [exception.terminate]) or destroying any objects with static or thread storage duration (6.9.3.4 [basic.start.term]).

If the execution of an atomic block evaluates any of the following outside of a manifestly constant-evaluated context (7.7 [expr.const]), the behavior is implementation-defined:

[ Note: Some functions in the standard library can be used in an atomic block (16.4.6.17 [atomic.use]). ] [ Note: The implementation may define that the behavior is undefined in some or all of the cases above. ]

[ Example:

int f()
{
  static int i = 0;
  atomic do {
    ++i;
    return i;
  }
}
Each invocation of f (even when called from several threads simultaneously) retrieves a unique value (ignoring overflow). -- end example ]

[ Note: Atomic blocks are likely to perform best where they execute quickly and touch little data. -- end note ]

Add 16.4.6.17 [atomic.use]:

16.4.6.17 Functions usable in an atomic block [atomic.use]

All library functions may be used in an atomic block (8.8 [stmt.tx]), except