2017-07-08 11 views
0

最近、メモリの再注文が行われています。私の質問は、マルチスレッドシナリオに関するものです。以下の例を考えてみましょう:メモリの順序付け、他の実行とマルチスレッドの安全性なし

A = 0; 
B = 0; 

Thread 1 on Processor 1      Thread 2 on Processor 2 

    A = 100;          while(B== 0); 
    B = 1;          //access A here 

私はX86-64 Windowsプラットフォーム上でコーディングし、AとBに格納する(コンパイラレベルまたはハードウェアレベルでのいずれか)並べ替えることができ、私が終わる可能性があると考えたことがないされていますスレッド2ではB = 0であり、Aはまだ0であることがわかります。このようなコードでは、問題や厄介なバグは発生しませんでした。それはx86-x64が強く注文されており、WindowsのCコンパイラも同様です。

弱い順序のメモリを持つ他のプラットフォームでこのようなコードを実行するには、ロック内でAとBを更新してアクセスする必要があります(基本的なロックの実装でメモリバリアが使用され、以前のすべてのロードおよびストアがすべてのプロセッサコアで表示された後にのみリリースされます)。

おかげ

答えて

1

強く注文したので、WindowsのCコンパイラがされているx86ベースのx64ので、それです。

実際、X86は、ストアの並べ替えを許可しない強く順序付けされたCPUです。したがって、すべてのCPUコアは、コンパイラによって発行された順序を観察します。

Bは、プロセッサ1でプロセッサ2上で読み込まれている間に変更されます。同期を行わないCメモリモデルでは許可されません(コンパイラの最大限の最適化を試してください)。

ロックはコア間の同期に使用できますが、Bで回転しているため問題がある可能性があります。ロックが獲得された状態でそれが発生した場合、プロセッサー1は値を更新できません。

正しい解決策は、Batomicです。それはすべてのレベルで正しい順序を保証します。

+0

LMimseyを最大限に活用すると、コンパイラレベルの並べ替えが可能になります。私は "これはCメモリモデルでは許可されていません"ということはありませんでした。強く順序付けられたx86は、上記の例が得ようとしているB = 1のときにA = 100を保証するはずです。 – san216

+0

また、私の質問の次の部分は、弱い順序のメモリを持つプラットフォームでは、ロック内でAとBの両方を更新するように気を付ける必要があります。すべてのOSプラットフォーム上のロックプリミティブは、ロック解除ロジックの内部にメモリバリアを挿入します。そうしないと、ロックがハードウェアメモリアクセスの順序変更を防ぐことができないためです。 – san216

+0

2つ以上のスレッドによる単一のメモリ位置への読み取り/書き込みアクセスは、メモリモデルルール(別名データ競合)に違反しています。結果は未定義の動作です。例えば、あなたのコンパイラは 'B'がコア2で更新されることを期待していないかもしれないので、単純にループから取り除くかもしれません。ループは決して終了しません。 – LWimsey

関連する問題