This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 114a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-04-18


740. Incorrect note on data races

Section: 6.9.2  [intro.multithread]     Status: CD2     Submitter: Wolf Lammen     Date: 3 November, 2008

[Voted into WP at March, 2010 meeting.]

6.9.2 [intro.multithread] paragraph 12 says,

A visible side effect A on an object M with respect to a value computation B of M satisfies the conditions:

The value of a non-atomic scalar object M, as determined by evaluation B, shall be the value stored by the visible side effect A. [Note: If there is ambiguity about which side effect to a non-atomic object is visible, then there is a data race, and the behavior is undefined. —end note]

The note here suggests that, except in the case of a data race, visible side effects to value computation can always be determined. But unsequenced and indeterminately sequenced side effects on the same object create ambiguities with respect to a later value computation as well. So the wording needs to be revisited, see the following examples.

    int main(){
      int i = 0;
      i = // unsequenced side effect A
      i++; // unsequenced side effect B
      return i; // value computation C
    }

According to the definition in the draft, both A and B are visible side effects to C. However, there is no data race, because (paragraph 14) a race involves at least two threads. So the note in paragraph 12 is logically false.

The model introduces the special case of indeterminately sequenced side effects, that leave open what execution order is taken in a concrete situation. If the execution paths access the same data, unpredictable results are possible, just as it is the case with data races. Whereas data races constitute undefined behavior, indeterminatedly sequenced side effects on the same object do not. As a consequence of this disparity, indeterminately sequenced execution occasionally needs exceptional treatment.

    int i = 0;
    int f(){
      return
      i = 1; // side effect A
    }
    int g(){
      return
      i = 2; // side effect B
    }
    int h(int, int){
      return i; // value computation C
    }
    int main(){
      return h(f(),g()); // function call D returns 1 or 2?
    }

Here, either A or B is the visible side effect on the value computation C, but you cannot tell which (cf. 6.9.1 [intro.execution] paragraph 16) . Although an ambiguity is present, it is neither because of a data race, nor is the behavior undefined, in total contradiction to the note.

Proposed resolution (October, 2009):

Change 6.9.2 [intro.multithread] paragraph 12 as follows:

...The value of a non-atomic scalar object or bit-field M, as determined by evaluation B, shall be the value stored by the visible side effect A. [Note: If there is ambiguity about which side effect to a non-atomic object or bit-field is visible, then there is a data race, and the behavior is either unspecified or undefined. —end note]...