5

この構造体を見てみましょう:

struct entry {
    atomic<bool> valid;
    atomic_flag writing;
    char payload[128];
}

2 つの踏面 A と B は、この構造体に次のように同時にアクセスします ( をeのインスタンスにしますentry)。

if (e.valid) {
    // do something with e.payload...
} else {
    while (e.writing.test_and_set(std::memory_order_acquire));
    if (!e.valid) {
       // write e.payload one byte at a time
       // (the payload written by A may be different from the payload written by B)
       e.valid = true;
       e.writing.clear(std::memory_order_release);
    }
}

このコードは正しく、問題はないと思いますが、なぜ機能するのかを理解したいと思います。

C++ 標準 (29.3.13) の引用:

実装では、妥当な時間内にアトミック ストアをアトミック ロードで認識できるようにする必要があります。

ここで、これを念頭に置いて、スレッド A と B の両方がelseブロックに入ると想像してください。このインターリーブは可能ですか?

  1. どちらもA出店Bするelseのでvalidfalse
  2. Awritingフラグを立てます
  3. Bwritingフラグをロックし始めます
  4. Avalidフラグ ( ) を読み取り、ブロックfalseに入るif
  5. Aペイロードを書き込みます
  6. Atrue有効なフラグに書き込みます。明らかに、もう一度A読み取ると、validtrue
  7. Awritingフラグをクリアします
  8. Bwritingフラグを立てます
  9. B有効フラグ ( false) の古い値を読み取り、ifブロックに入る
  10. Bペイロードを書き込みます
  11. B旗に書いtrueてますvalid
  12. Bwritingフラグをクリアします

出来ないことを願っていますが、実際に「なぜ出来ないのか」という質問に答えようとすると、答えがわかりません。これが私の考えです。

標準からの引用(29.3.12):

アトミックな read-modify-write 操作は、read-modify-write 操作に関連付けられた書き込みの前に書き込まれた (変更順序での) 最後の値を常に読み取る必要があります。

atomic_flag::test_and_set()29.7.5 で述べられているように、アトミックな read-modify-write 操作です。

atomic_flag::test_and_set()は常に「新しい値」を読み取り、std::memory_order_acquireメモリの順序付けで呼び出しているため、フラグの古い値を読み取ることはできません。これは、呼び出し (を使用する)の前にvalid発生するすべての副作用を確認する必要があるためです。Aatomic_flag::clear()std::memory_order_release

私は正しいですか?

説明。私の推論全体 (間違っているか正しいか) は 29.3.12 に依存しています。ここまででわかったのは、 を無視すれば、であってもatomic_flagから古いデータを読み取ることができるということです。すべてのスレッドに「常にすぐに見える」という意味ではないようです。求めることができる最大の保証は、読み取る値の一貫した順序ですが、新しいデータを取得する前に古いデータを読み取ることはできます。幸いなことに、すべての操作にはこの重要な機能があります。つまり、常に新しいデータを読み取ります。したがって、( だけでなく) フラグを取得/解放した場合にのみ、期待される動作が得られます。私の主張がわかりましたか (正しいかどうか)?validatomicatomicatomic_flag::test_and_set()exchangewritingvalid


編集:私の最初の質問には、質問の核心と比較するとあまりにも多くの注目を集めた次の数行が含まれていました。すでに出された回答との一貫性のためにそれらを残していますが、今質問を読んでいる場合は無視してください.

プレーンでvalidatomic<bool> はなくプレーンでboolatomic<bool> あることには意味がありますか? さらに、それが である必要がある場合、問題を引き起こさない「最小」メモリ順序制約は何ですか?

4

4 に答える 4

2
于 2013-06-04T19:49:34.110 に答える
1

validがアトミックでない場合e.valid、最初の行の の最初の読み取りが への代入と競合しe.validます。

いずれかのスレッドがスピンロックを取得する前に、両方のスレッドが読み取りを完了しているという保証はありません。つまり、ステップ 1 と 6 は順序付けされていません。

于 2013-06-04T18:19:41.317 に答える
1

e.valid へのストアは解放する必要があり、条件でのロードは取得する必要があります。それ以外の場合、コンパイラ/プロセッサは、ペイロードを書き込む上で e.valid を自由に設定できます。このようなコードを C/C++11 メモリ モデルに対して検証するためのオープンソース ツール CDSChecker があります。

于 2013-09-02T05:00:10.367 に答える