単一プロセッサの複数のコアの場合、MESI は、プロセッサのコア間で共有される L3 キャッシュを介して動作します。
MESI はすべてのキャッシュ レベルで動作します。一部のプロセッサ設計では、L3 キャッシュがコア間の効率的な「スイッチボード」として機能します。たとえば、L3 キャッシュが包括的であり、CPU の L1 または L2 キャッシュにすべてを保持している場合、L3 キャッシュに何かがないことを知るだけで、それが他のコアのキャッシュにないことがわかります。これにより、必要なスヌーピングの量を減らすことができます。ただし、これらは高度な最適化です。
複数のプロセッサ (共有 L3 なし) の場合、MESI はメイン メモリを介して動作します。
ここで何を言おうとしているのかはわかりませんが、真実とは一致していないようです。MESI はキャッシュ間で動作します。メモリはキャッシュではないため、MESI プロトコルに参加する必要はありません。
L3 キャッシュのない CPU の場合、L2 キャッシュ間 MESI トラフィックは、メイン メモリに接続するバスと同じ CPU バスで発生します。これは、CPU にオンチップ メモリ コントローラーが搭載される前は、一部のマルチチップ CPU 設計に当てはまりました。しかし、今日、ほとんどのラップトップ/デスクトップ マルチコア CPU にはメモリ コントローラーが搭載されているため、メモリに接続するバスはメモリにのみ接続します。したがって、そこには MESI トラフィックはありません。データが 1 つのコアの L2 キャッシュにあり、別のコアの L2 キャッシュに到達する必要がある場合、メモリを超えません。(コアとメモリ コントローラーのトポロジーを考えてみてください。それは正気ではありません。)
複数のスレッドによって読み書きされるグローバル変数を使用する場合、volatile 型指定子を使用して、望ましくない最適化を防ぎ、レジスター (L1-3 キャッシュではなく) でのキャッシュを防ぎます。
これが真実である言語を私は知りません。C/C++ では、volatile
マルチスレッドではないシグナルのようなものは当てはまりません (少なくとも、明確に定義されたマルチスレッド API を備えたプラットフォームでは)。volatile
また、レジスタとは関係のない特定の言語セマンティクスを持つJava のようなものには当てはまりません。
したがって、値がレジスタではなくキャッシュまたはメイン メモリにある場合、MESI は、スレッドがグローバルの正しい値を認識できるように作業を行います。
これは、ハードウェア/アセンブラー レベルで当てはまります。そこにレジスターが存在します。しかし実際には、MESI によってメモリ キャッシュが一貫したものになる一方で、最近の CPU には同じ種類の問題を引き起こす他の最適化があるためではありません。たとえば、CPU は読み取りをプリフェッチしたり、順不同で書き込みを遅らせたりする場合があります。したがって、MESI に加えてメモリ バリアのようなものが必要です。もちろん、これは非常にプラットフォーム固有になります。
MESI は最適化と考えることができます。スレッド間メモリの可視性が正しく機能するためには、プラットフォームが必要とすることは何でも行う必要があります。しかし、MESI はその仕事を大幅に減らします。
たとえば、MESI を使用しないと、あるコアから別のコアにデータを取得する唯一の方法が、メイン メモリへの書き込みと、その書き込みの完了を待ってからメイン メモリからの読み取りを行うことになるような設計になる可能性があります。それは完全な災害になるでしょう。まず、別のスレッドが必要とする場合に備えて、メイン メモリにフラッシュする必要があります。次に、このすべてのトラフィックが通常のメモリ トラフィックを妨害します。うん。