1442. "happens-before" should be "synchronizes-with"

Section: 33 [thread] Status: NAD Editorial Submitter: Canada Opened: 2010-08-25 Last modified: 2016-02-10

Priority: Not Prioritized

View all other issues in [thread].

View all issues with NAD Editorial status.

Duplicate of: 1443

Discussion:

Addresses CA-9, GB-122

[CA-9:]

Imposed happens-before edges should be in synchronizes-with
Each use of the words "happens-before" should be replaced with the words "synchronizes-with" in the following sentences:
27.2.3p2
30.3.1.2p6
30.3.1.5p7
30.6.4p7
30.6.9p5
30.6.10.1p23
Rationale: Happens-before is defined in 1.10p11 in a way that (deliberately) does not make it explicitly transitively closed. Adding edges to happens-before directly, as in 27.2.3p2 etc., does not provide transitivity with sequenced-before or any other existing happens-before edge. This lack of transitivity seems to be unintentional.

[GB-122]

At various points in the standard new edges are added to happens-before, for example 27.2.3:2 adds happens-before edges between writes and reads from a stream:

If one thread makes a library call a that writes a value to a stream and, as a result, another thread reads this value from the stream through a library call b such that this does not result in a data race, then a happens before b.

Happens-before is defined in 1.10:11 in a deliberate way that makes it not explicitly transitively closed. Adding edges to happens-before directly, as in 27.2.3:2, does not provide transitivity with sequenced-before or any other existing happens-before edge. This lack of transitivity seems to be unintentional. In order to achieve transitivity we suggest each edge be added to inter-thread-happens-before as a synchronises-with edge (as per conversation with Hans Boehm). In the standard, each use of the words "happens-before" should be replaced with the words "synchronizes-with" in the following sentences:

27.2.3:2, 30.3.1.2:6, 30.3.1.5:7, 30.6.4:7, 30.6.9:5, 30.6.10.1:23

Proposed resolution:

[Beman provided specific wording for the proposed resolution.]

Change 27.2.3 Thread Safety [iostreams.threadsafety] paragraph 2:

If one thread makes a library call a that writes a value to a stream and, as a result, another thread reads this value from the stream through a library call b such that this does not result in a data race, then a happens before synchronizes with b.

Change 30.3.1.2 thread constructors [thread.thread.constr] paragraph 6:

Synchronization: The invocation of the constructor happens before synchronizes with the invocation of the copy of f.

Change 30.3.1.5 thread members [thread.thread.member] paragraph 7:

Synchronization: The completion of the thread represented by *this happens before synchronizes with (1.10) join() returns returning. [ Note: Operations on *this are not synchronized. --end note ]

Change 30.6.4 Associated asynchronous state [futures.state] paragraph 7:

Calls to functions that successfully set the stored result of an associated asynchronous state synchronize with (1.10) calls to functions successfully detecting the ready state resulting from that setting. The storage of the result (whether normal or exceptional) into the associated asynchronous state happens before synchronizes with (1.10) that state is being set to ready.

Change 30.6.9 Function template async [futures.async] paragraph 5:

Synchronization: the invocation of async happens before synchronizes with (1.10) the invocation of f. [ Note: this statement applies even when the corresponding future object is moved to another thread. — end note ] If the invocation is not deferred, a call to a waiting function on an asynchronous return object that shares the associated asynchronous state created by this async call shall block until the associated thread has completed. If the invocation is not deferred, the join() on the created thread happens before synchronizes with (1.10) the first function that successfully detects the ready status of the associated asynchronous state returns or before the function that gives up the last reference to the associated asynchronous state returns, whichever happens first. If the invocation is deferred, the completion of the invocation of the deferred function happens before synchronizes with the calls to the waiting functions return.

Change 30.6.10.1 packaged_task member functions [futures.task.members] paragraph 23:

Synchronization: a successful call to operator() synchronizes with (1.10) a call to any member function of a future, shared_future, or atomic_future object that shares the associated asynchronous state of *this. The completion of the invocation of the stored task and the storage of the result (whether normal or exceptional) into the associated asynchronous state happens before synchronizes with (1.10) the state is being set to ready. [ Note: operator() synchronizes and serializes with other functions through the associated asynchronous state. —end note ]