11

Javaで、次の変数を共有する2つのスレッドがある場合:

int a;
volatile int b;

スレッド1が行う場合:

a = 5;
b = 6;

次に、これら2つの命令の間にStoreStoreバリアが挿入され、「a」がメインメモリにフラッシュバックされます。

スレッド2がそうする場合:

if(b == 6)
 a++;

LoadLoadバリアが間に挿入され、「b」の新しい値が表示された場合、「a」の新しい値も表示されることが保証されます。しかし、これは実際にどのように達成されますか?LoadLoadはCPUキャッシュ/レジスタを無効にしますか?または、CPUから再びvolatileから読み取った後の変数の値をフェッチするようにCPUに指示しますか?

LoadLoadバリアに関するこの情報を見つけました(http://gee.cs.oswego.edu/dl/jmm/cookbook.html):

LoadLoadバリアシーケンス:Load1; LoadLoad; Load2は、Load2がアクセスするデータの前に、Load1のデータがロードされ、後続のすべてのロード命令がロードされることを保証します。一般に、明示的なLoadLoadバリアは、投機的ロードや、待機中のロード命令が待機中のストアをバイパスできる順不同の処理を実行するプロセッサに必要です。常に負荷の順序を維持することを保証するプロセッサでは、障壁はノーオペレーションになります。

しかし、これがどのように達成されるかは実際には説明されていません。

4

2 に答える 2

4

これがどのように達成されるかについて、一例を挙げます。詳細については、こちらをご覧ください。あなたが示したように、x86プロセッサの場合、LoadLoadはノーオペレーションになります。私がリンクした記事の中で、Mark は次のように指摘しています。

Doug は、StoreStore、LoadLoad、および LoadStore を一覧表示します

したがって、本質的に必要なバリアは、x86 アーキテクチャの StoreLoad だけです。では、これは低レベルでどのように達成されるのでしょうか?

これはブログからの抜粋です:

揮発性読み取りと不揮発性読み取りの両方に対して生成されたコードは次のとおりです。

nop                       ;*synchronization entry
mov    0x10(%rsi),%rax    ;*getfield x

揮発性書き込みの場合:

xchg   %ax,%ax
movq   $0xab,0x10(%rbx)
lock addl $0x0,(%rsp)     ;*putfield x

命令は、Dougのlockクックブックに記載されている StoreLoad です。ただし、ロック命令は、リストされているように、すべての読み取りを他のプロセスと同期します

ロックされた命令を使用して、あるプロセッサによって書き込まれたデータと別のプロセッサによって読み取られたデータを同期させることができます。

これにより、揮発性ロードに対して LoadLoad LoadStore バリアを発行するオーバーヘッドが削減されます。

そうは言っても、アッシリアが指摘したことを繰り返します。それが起こる方法は、開発者にとって重要ではありません (プロセッサ/コンパイラの実装者に興味がある場合は別の話です)。キーワードは一種のvolatileインターフェースです

  1. 別のスレッドによって書き込まれた最新の読み取りを取得します
  2. JIT コンパイラーの最適化に悩まされることはありません。
于 2013-03-12T12:46:39.627 に答える
0

その LoadLoad が no-op と評価された場合、スレッド 2 はキャッシュされた値を引き続き使用できます。

これは、クックブックの「注文可能」表でカバーされています。

プログラミングの順番は

read b
read a
write a

「キャッシュする」とは、コードが並べ替えられることを意味します

read a
...
read b

この並べ替えは禁止されています。

于 2013-03-12T15:40:44.413 に答える