forked from lwg/issues
-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New issue from jim x: "The read exclusive ownership of an atomic read…
…-modify-write operation and whether its read and write are two operations are unclear"
- Loading branch information
Showing
1 changed file
with
120 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 <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(); | ||
} | ||
</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> |