3980. The read exclusive ownership of an atomic read-modify-write operation and whether its read and write are two operations are unclear

Section: 32.5.4 [atomics.order] Status: Tentatively NAD Submitter: jim x Opened: 2023-08-22 Last modified: 2023-11-03

Priority: Not Prioritized

View other active issues in [atomics.order].

View all other issues in [atomics.order].

View all issues with Tentatively NAD status.

Discussion:

Such two questions are sourced from StackOverflow:

  1. Can the read operations in compare_exchange_strong in different two thread read the same value?

  2. For purposes of ordering, is atomic read-modify-write one operation or two?

Given this example:

#include <iostream>
#include <atomic>
#include <thread>

struct SpinLock{
  std::atomic<bool> atomic_;
  void lock(){
    bool expected = false;
    while (!atomic_.compare_exchange_strong(expected,true,std::memory_order_release,std::memory_order_relaxed)) {
    }
  }
  void unlock(){
    atomic_.store(false, std::memory_order_release);
  }
};

int main(){
  SpinLock spin{false};
  auto t1 = std::thread([&](){
    spin.lock();
    spin.unlock();
  });
  auto t2 = std::thread([&](){
    spin.lock();
    spin.unlock();
  });
  t1.join();
  t2.join();
}

In the current draft, the relevant phrasing that can interpret that only one read-modify-write operation reads the initial value false is 32.5.4 [atomics.order] p10:

Atomic read-modify-write operations shall always read the last value (in the modification order) written before the write associated with the read-modify-write operation.

However, the wording can have two meanings, each kind of read can result in different explanations for the example

  1. The check of the violation is done before the side effect of the RMW is in the modification order, i.e. the rule is just checked at the read point.

  2. The check of the violation is done after the side effect of the RMW is in the modification order, i.e. the rule is checked when RMW tries to add the side effect that is based on the read-value to the modification order, and that side effect wouldn't be added to the modification order if the rule was violated.

With the first interpretation, the two RMW operations can read the same initial value because that value is indeed the last value in the modification order before such two RMW operations produce the side effect to the modification order.

With the second interpretation, there is only one RMW operation that can read the initial value because the latter one in the modification order would violate the rule if it read the initial value.

Such two interpretations arise from that the wording doesn't clearly specify when that check is performed.

So, my proposed wording is:

Atomic read-modify-write operations shall always read the value from a side effect X, where X immediately precedes the side effect of the read-modify-write operation in the modification order.

This wording keeps a similar utterance to 6.9.2.2 [intro.races], and it can clearly convey the meaning that we say the value read by RWM is associated with the side effect of RMW in the modification order.

Relevant discussion can be seen CWG/issues/423 here.

[2023-11-03; Reflector poll]

NAD. The first reading isn't plausible.

Proposed resolution:

This wording is relative to N4958.

  1. Modify 32.5.4 [atomics.order] as indicated:

    -10- Atomic read-modify-write operations shall always read the last value from a side effect X, where X immediately precedes the side effect of the read-modify-write operation (in the modification order) written before the write associated with the read-modify-write operation.

    -11- Implementations should make atomic stores visible to atomic loads within a reasonable amount of time.