進行中の最適化:CppMem によるシーケンシャルの一貫性

アトミック データ型を使用すると、プログラムをニーズに合わせて調整し、最適化できます。しかし今、私たちはマルチスレッドの専門家の領域にいます.

順次一貫性

メモリ モデルを指定しない場合は、順次整合性が使用されます。順次整合性により、2 つのプロパティが保証されます。各スレッドはソース コードの順序で命令を実行し、すべてのスレッドはグローバルな順序に従います。

66
78

この知識は、プログラムを分析するのに十分です。 x と y はアトミックであるため、プログラムに競合状態はありません。ということで、質問のみです。 x と y の可能な値は?しかし、質問は簡単です 答える。シーケンシャルの一貫性のため、すべてのスレッドはグローバルな順序に従う必要があります。

以下を保持します:

<オール>
  • x.store(2000); 以前の出来事 y.store(11);
  • std::cout <以前の出来事 std::cout <

    したがって、y.load() が 11 の場合、x.load() に 0 を指定することはできません。これは、x.store(2000) が y.store(11) の前に発生するためです。

    x と y の他のすべての値が可能です。 x と y に対して 3 つの異なる結果を生成する 3 つの可能なインターリーブを次に示します。

    <オール>
  • スレッド 1 は、スレッド 2 の前に完全に実行されます。
  • スレッド 2 はスレッド 1 の前に完全に実行されます。
  • thread2 が完全に実行される前に、thread1 が最初の命令 x.store(2000) を実行します。
  • ここでは、x と y のすべての値。

    では、これは CppMem ではどのように見えるでしょうか。

    CppMem

    85
    95

    最初に CppMem の構文を少し説明します。 CppMem は 2 行目と 3 行目で std::atomic の typedef atomic_int を使用します。

    プログラムを実行すると、実行候補の数の多さに圧倒されます。

    384 (1) ) 可能な実行候補のうち、一貫しているのは 6 つだけです。どの候補者もデータ競争をしていません。それはどのように機能しますか?

    しかし、私は一貫した実行にのみ興味があります。インターフェイスを使用します (2 ) 6 つの注釈付きグラフを分析します。他の (378) は一貫していません。つまり、たとえば、変更順序を尊重しません。だから私はそれらを完全に無視します。

    y=11 と x=0 を除いて、x と y のすべての値が可能であることは既にわかっています。これは、既定のメモリ モデルによるものです。

    質問は次のとおりです。スレッドのどのインターリーブが x と y のどの値を生成しますか?注釈付きグラフ (CppMem - 概要) で記号を既に紹介しているため、分析は x と y の結果に集中します。

    (y=0, x=0) の実行

    (y=0, x=2000) の実行

    (y=11, x=2000) の実行

    グラフで赤い数字を使用した理由がわかりますか?分析が終わっていないからです。

    より深い洞察

    次の図の 6 つの異なるスレッドのインターリーブを見ると、質問がありますか?どのグラフに対応する一連の命令は?これが解決策です。各命令シーケンスに対応するグラフを割り当てました。

    命令のシーケンス

    より単純なケースから始めます:

    • (1) :グラフ (1) をシーケンス (1) に割り当てるのは非常に簡単です。シーケンス (1) では、x と y の値は 0 です。これは、操作 x.store(2000) と y.store(11) の前に y.load() と x.load() が実行されるためです。
    • (6) :実行 (6) の議論はそれに応じています。すべてのストア操作の後にすべてのロード操作が発生した場合、y の値は 11 になり、y の値は 2000 になります。
    • (2)、(3)、(4)、(5): ここで、y の値が 0 で x の値が 2000 である、より興味深いケースについて説明します。黄色の矢印 (sc) は、一連の命令を表すため、私の推論の鍵です。たとえば、実行 (2) を見てみましょう .
      • (2) :グラフ内の黄色の矢印 (sc) のシーケンス (2) x=2000 の書き込み => y=0 の読み取り => y=11 の書き込み => x=2000 の読み取り。このシーケンスは、スレッド (2) の 2 番目のインターリーブの命令シーケンスに対応 .

    次は?

    次の投稿では、順序の一貫性を破ります。では、取得と解放のセマンティックに基づく最適化を行うとどうなるでしょうか?