誰かがこの声明を説明できますか:
shared variables
x = 0, y = 0
Core 1 Core 2
x = 1; y = 1;
r1 = y; r2 = x;
x86 プロセッサr1 == 0
を使用するにはどうすればよいですか?r2 == 0
Bartosz Milewski によるソース「The Language of Concurrency」。
誰かがこの声明を説明できますか:
shared variables
x = 0, y = 0
Core 1 Core 2
x = 1; y = 1;
r1 = y; r2 = x;
x86 プロセッサr1 == 0
を使用するにはどうすればよいですか?r2 == 0
Bartosz Milewski によるソース「The Language of Concurrency」。
この問題は、命令の並べ替えを伴う最適化が原因で発生する可能性があります。言い換えれば、両方のプロセッサは、変数およびを割り当てる前r1
におよびを割り当てることができます。これによりパフォーマンスが向上することがわかった場合。これは、順序制約を強制するメモリ バリアを追加することで解決できます。r2
x
y
投稿で言及したスライドショーを引用するには:
最新のマルチコア/言語は、シーケンシャルな一貫性を壊します。
x86 アーキテクチャーに関しては、Intel® 64 and IA-32 Architectures Software Developer's Manual (Chapter 8.2 Memory Ordering ) を読むのが最適なリソースです。セクション 8.2.1 および 8.2.2 では、Intel486、Pentium、Intel Core 2 Duo、Intel Atom、Intel Core Duo、Pentium 4、Intel Xeon、および P6 ファミリ プロセッサによって実装されるメモリ順序について説明します。これは、プロセッサ順序と呼ばれるメモリ モデルです。古い Intel386 アーキテクチャのプログラムの順序付け(強い順序付け) とは対照的です (読み取りおよび書き込み命令は常に、命令ストリームに出現した順序で発行されます)。
このマニュアルでは、プロセッサの順序付けメモリ モデルに関する多くの順序付けの保証 ( Loads are not reordered with other load、Stores are not reordered with other stores、Stores are not reordered with older loadなど) について説明していますが、許可されている並べ替え規則についても説明しています。これにより、OP の投稿で競合状態が発生します。
8.2.3.4 ロードは以前のストアで別の場所に並べ替えられる場合がある
一方、命令の元の順序が入れ替わった場合:
shared variables
x = 0, y = 0
Core 1 Core 2
r1 = y; r2 = x;
x = 1; y = 1;
この場合、プロセッサは状況が許可されないことr1 = 1
を保証します ( 8.2.3.3 Stores Are Not Reordered With Early Load保証のため)。つまり、これらの命令は個々のコアで決して並べ替えられません。r2 = 1
これをさまざまなアーキテクチャと比較するには、次の記事を参照してください: Memory Ordering in Modern Microprocessors . Itanium (IA-64) が IA-32 アーキテクチャよりもさらに多くの並べ替えを行っていることがわかります。
弱いメモリ整合性モデル(SPARC、PowerPC、Itanium、ARMなど)を備えたプロセッサでは、明示的なメモリバリア命令なしの書き込みで強制的なキャッシュコヒーレンシがないため、上記の状態が発生する可能性があります。つまり、基本的には前にCore1
書き込みが表示されますが、前に書き込みが表示されますx
y
Core2
y
x
。この場合、完全なフェンス命令は必要ありません...基本的には、このシナリオで書き込みまたは解放のセマンティクスを適用するだけで、すべての書き込みがコミットされ、すべてのプロセッサに表示されてから、読み取りが行われた変数が実行されます。に書かれています。x86のような強力なメモリ整合性モデルを備えたプロセッサアーキテクチャでは、通常、これは不要ですが、Grooが指摘しているように、コンパイラ自体が操作を並べ替えることができます。CおよびC++でキーワードを使用してvolatile
、特定のスレッド内でコンパイラーによる操作の並べ替えを防ぐことができます。それはvolatile
、スレッド間の読み取りと書き込みの可視性を管理するスレッドセーフなコードを作成するということではありません...メモリバリアが必要になります。だからvolatile
それでも安全でないスレッドコードを作成する可能性があり、特定のスレッド内で、コンパイルされたマシンコードレベルで逐次一貫性を強制します。
問題は、2つのステートメントが相互に依存していないため、どちらのスレッドも2つのステートメント間の順序付けを強制しないことです。
コンパイラーは、xとyがエイリアス化されていないことを認識しているため、操作を順序付ける必要はありません。
CPUは、xとyがエイリアス化されていないことを認識しているため、速度を上げるためにそれらを並べ替えることができます。これが発生する良い例は、CPUが書き込み結合の機会を検出した場合です。コヒーレンシモデルに違反することなくマージできる場合は、ある書き込みを別の書き込みとマージできます。
相互依存関係は奇妙に見えますが、実際には他の競合状態と同じです。共有メモリスレッドコードを直接記述することは非常に困難です。そのため、並列ハザードを小さなカーネルに分離し、アプリケーション自体からハザードを取り除くために、並列言語とメッセージパッシング並列フレームワークが開発されました。