私は最近、メモリバリアの cpu の推移性を読みましたが、著者は、一般的なバリアのみが推移性を保証できると強調しています。でも、よくわかりません。例えば:
CPU 1 CPU 2 CPU 3
======================= ======================= =======================
{ X = 0, Y = 0 }
STORE X=1 LOAD X STORE Y=1
<read barrier> <general barrier>
LOAD Y LOAD X
X が CPU3 のキャッシュでステータスが変更され、Y が CPU2 のキャッシュでステータスも変更されたとします。
読み取りバリアの前に書き込みバリアを追加すると、CPU1 はそのストア バッファを CPU2 と共有します。(一般バリアとなります)
1) CPU1 はストアバッファに X(X=1) の値を設定します。
2) CPU2 は、ストア バッファ (共有ストア バッファ) から X の値を読み取ります。
3) CPU2 はストア バッファ (書き込みバリア) で X をマークし、無効化キューを読み取り、CPU3 からの無効化メッセージがないことを確認します (読み取りバリア)。
4) CPU2 は、X のキャッシュ ラインを無効から変更済みに変更したいので、無効化メッセージを CPU3 に送信します。
5) CPU3 は X の無効化メッセージを受信し、無効化キューに入れ、CPU2 に応答します。
6) CPU2 は応答を受信し、X = 1 をメモリまたはキャッシュに書き込み、Y == 0 をロードします。
...
7) CPU3 は、ジェネラル バリアを実行すると、無効化されたキューに X の無効化メッセージがあることを検出します。その後、X は 1 に等しくなければなりません。
わかります。ただし、perbook の図 14.3 から別の例を読みました。
thread0(void) {
A = 1;
smp_wb();
B = 1;
}
thread1(void) {
while (B == 0)
continue;
barrier();
C = 1;
}
thread2(void) {
while (C == 0)
continue;
barrier();
assert(A == 1);
}
アサートを発射する機会がいくつかあります。Quick Quiz 14.2 の回答で、すべてのバリアを smp_mb に変更すると修正できると著者は述べています。
では、私の質問は、なぜスレッド 1 のバリアを smp_mb に変更する必要があるのですか? スレッド 0 とスレッド 1 が CPU0 と CPU1 で実行され、それらがストア バッファを共有している場合です。スレッド 1 が Store C = 1 を実行した後、それらのストア バッファは吹き飛ばされます。
[A(wb)、B、C]
スレッド 2 (CPU2 で実行) もバリアの代わりに smp_mb を使用するため、C == 1 が表示される場合、A が 1 でなければならないことが保証されます。
上記のすべてを MESI メモリ コヒーレンシ プロトコルで説明します。作者は、CPU の推移性を保証するために、smp_mb の代わりにスレッド 1 にバリアを作成する別のプロトコルがあることを意味するのでしょうか?
誰か私に例を教えてください。
特定のプロトコルでの推移性について考えるのは間違いかもしれません。覚えておかなければならないことは、非常に多くの異なるプロトコルとアーキテクチャーがあるため、rmb() または wmb() は CPU の推移性を保証できないということです。