11

私は主に C++ のバックグラウンドから来ていますが、この質問はどの言語のスレッドにも当てはまると思います。シナリオは次のとおりです。

  1. 2 つのスレッド (ThreadA と ThreadB) があり、共有メモリに値 x があります。

  2. x へのアクセスがミューテックス (または他の適切な同期制御) によって適切に制御されていると仮定します。

  3. スレッドが異なるプロセッサで実行された場合、ThreadA が書き込み操作を実行し、そのプロセッサが結果をメイン メモリではなく L2 キャッシュに配置するとどうなるでしょうか? 次に、ThreadB が値を読み取ろうとすると、独自の L1/L2 キャッシュ/メイン メモリを調べて、そこにあった古い値を操作するだけではないでしょうか?

そうでない場合、この問題はどのように管理されていますか?

もしそうなら、それについて何ができるでしょうか?

4

4 に答える 4

12

あなたの例はうまくいくでしょう。

複数のプロセッサは、MESIなどのコヒーレンシ プロトコルを使用して、キャッシュ間でデータの同期を維持します。MESI では、各キャッシュ ラインは、変更されているか、排他的に保持されているか、CPU 間で共有されているか、または無効であると見なされます。プロセッサ間で共有されるキャッシュ ラインを書き込むと、他の CPU では強制的に無効になり、キャッシュの同期が維持されます。

しかし、これでは十分ではありません。プロセッサーが異なればメモリー・モデルも異なり、最新のプロセッサーのほとんどは、メモリー・アクセスの順序変更をある程度サポートしています。このような場合、メモリバリアが必要です。

たとえば、スレッド A がある場合:

DoWork();
workDone = true;

そしてスレッドB:

while (!workDone) {}
DoSomethingWithResults()

両方が別々のプロセッサで実行されているため、DoWork() 内で行われた書き込みが、workDone への書き込みと DoSomethingWithResults() が一貫性のない状態で続行される前にスレッド B に表示されるという保証はありません。メモリ バリアは、読み取りと書き込みの順序をある程度保証します。スレッド A の DoWork() の後にメモリ バリアを追加すると、DoWork によって行われたすべての読み取り/書き込みが、workDone への書き込みの前に完了し、スレッド B が一貫したビューを取得できるようになります。ミューテックスは本質的にメモリバリアを提供するため、読み取り/書き込みはロックとロック解除の呼び出しを渡すことができません。

あなたの場合、あるプロセッサが他のプロセッサにキャッシュラインを汚したことを通知し、他のプロセッサにメモリからのリロードを強制します。値を読み書きするミューテックスを取得することで、メモリへの変更が期待される順序で他のプロセッサに表示されることが保証されます。

于 2009-07-09T17:57:41.763 に答える