アトミック変数が取得と解放のペアで古い値をロードできるかどうかを考えています。アトミック変数 x があり、その変数を解放セマンティクスで格納し、後で取得セマンティクスでロードするとします。理論上、古い値を読み取ることは可能ですか?
std::atomic<int> x = 0;
void thread_1()
{
x.store(1, std::memory_order_release);
}
void thread_2()
{
assert(x.load(std::memory_order_acquire) != 0);
}
スレッド 2 が x をロードしたときに関数スレッド 1 が終了した場合 (したがって、新しい値が格納されます)、スレッド 2 が x から古い値をロードすることは可能ですか? 言い換えれば、ロードの前に x への実際のストアが行われた場合、アサートが発生する可能性はありますか?
インターネットの記事から理解した限りでは可能ですが、その理由はわかりません。x へのストアによって生成されるメモリ フェンスはストア バッファを空にすることを保証しますが、x からのロードでのメモリ フェンスの取得はキャッシュ ラインを無効にすることが保証されるため、最新の値を読み取る必要があります。
追加した
acquire-release 自体には強制的な順序付けがないということですか? リリース前に行われたことはすべてリリース前に行われ、取得後に行われたことはすべてその後に行われるため、取得とリリースのペアは他の操作で順序付けを強制します (なぜ??)。私はそれを正しく理解しましたか?コードでは、次のアサートが発火しないことが保証されているということですか
std::atomic<int> x = 0;
std::atomic<int> y = 0;
void thread_1()
{
y.store(1, std::memory_order_relaxed);
x.store(1, std::memory_order_release);
}
void thread_2()
{
x.load(std::memory_order_acquire);
assert(y.load(std::memory_order_relaxed) != 0);
}
もちろん、スレッド1がすでにストアを終了している場合も同様です。x.load を while (x.load() == 0) に置き換えると、これは 100% 機能しますが、これが機能する原因はわかりません。
そして、コードを次のコードに置き換えるとどうなりますか
std::atomic<int> x = 0;
void thread_1()
{
x.exchange(1, std::memory_order_acq_rel);
}
void thread_2()
{
assert(x.exchange(0, std::memory_order_acq_rel) != 0);
}
それは何かを変えますか?
ありがとう。