Skip to content

Commit

Permalink
New issue from jim x: "The read exclusive ownership of an atomic read…
Browse files Browse the repository at this point in the history
…-modify-write operation and whether its read and write are two operations are unclear"
  • Loading branch information
Dani-Hub committed Sep 23, 2023
1 parent d2e8ee7 commit 2306e3e
Showing 1 changed file with 120 additions and 0 deletions.
120 changes: 120 additions & 0 deletions xml/issue3980.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?xml version='1.0' encoding='utf-8' standalone='no'?>
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">

<issue num="3980" status="New">
<title>The read exclusive ownership of an atomic read-modify-write operation and whether its read and write are two operations are unclear</title>
<section><sref ref="[atomics.order]"/></section>
<submitter>jim x</submitter>
<date>22 Aug 2023</date>
<priority>99</priority>

<discussion>
<p>
Such two questions are sourced from StackOverflow:
</p>
<ol>
<li><p><a href="https://stackoverflow.com/questions/77126045/can-the-read-operations-in-compare-exchange-strong-in-different-two-thread-rea/77126363?noredirect=1#comment135968355_77126363">Can the read operations in <tt>compare_exchange_strong</tt> in different two thread read the same value?</a></p></li>
<li><p><a href="https://stackoverflow.com/questions/65568185/for-purposes-of-ordering-is-atomic-read-modify-write-one-operation-or-two">For purposes of ordering, is atomic read-modify-write one operation or two?</a></p></li>
</ol>
<p>
Given this example:
</p>
<blockquote>
<pre>
#include &lt;iostream&gt;
#include &lt;atomic&gt;
#include &lt;thread&gt;

struct SpinLock{
std::atomic&lt;bool&gt; 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([&amp;](){
spin.lock();
spin.unlock();
});
auto t2 = std::thread([&amp;](){
spin.lock();
spin.unlock();
});
t1.join();
t2.join();
}
</pre>
</blockquote>
<p>
In the current draft, the relevant phrasing that can interpret that only one read-modify-write operation reads the initial
value false is <sref ref="[atomics.order]"/> p10:
</p>
<blockquote style="border-left: 3px solid #ccc;padding-left: 15px;"><p>
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.
</p></blockquote>
<p>
However, the wording can have two meanings, each kind of read can result in different explanations for the example
</p>
<ol>
<li><p>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.</p></li>
<li><p>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 <tt>RMW</tt> 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.</p></li>
</ol>
<p>
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.
<p/>
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.
<p/>
Such two interpretations arise from that the wording doesn't clearly specify when that check is performed.
<p/>
So, my proposed wording is:
</p>
<blockquote style="border-left: 3px solid #ccc;padding-left: 15px;"><p>
Atomic read-modify-write operations shall always read the value from a side effect <tt>X</tt>, where <tt>X</tt>
immediately precedes the side effect of the read-modify-write operation in the modification order.
</p></blockquote>
<p>
This wording keeps a similar utterance to <sref ref="[intro.races]"/>, and it can clearly convey the meaning
that we say the value read by <tt>RWM</tt> is associated with the side effect of <tt>RMW</tt> in the modification order.
<p/>
Relevant discussion can be seen <a href="https://github.com/cplusplus/CWG/issues/423">CWG/issues/423</a> here.
</p>
</discussion>

<resolution>
<p>
This wording is relative to <paper num="N4958"/>.
</p>

<ol>

<li><p>Modify the <sref ref="[atomics.order]"/> as indicated:</p>

<blockquote>
<p>
-10- Atomic read-modify-write operations shall always read the <del>last</del> value <ins>from a side effect <i>X</i>,
where <i>X</i> immediately precedes the side effect of the read-modify-write operation</ins> <del>(</del>in the
modification order<del>) written before the write associated with the read-modify-write operation</del>.
<p/>
-11- Implementations should make atomic stores visible to atomic loads within a reasonable amount of time.
</p>
</blockquote>

</li>

</ol>
</resolution>

</issue>

0 comments on commit 2306e3e

Please sign in to comment.