な連動を可視にすべてのスレッド?
-
21-08-2019 - |
質問
ることもあって、変数の"カウンター"が複数のスレッドがアクセスし、この値を設定する"カウンター"に連動する:
int value = Interlocked.Increment(ref counter);
や
int value = Interlocked.Decrement(ref counter);
きになっているのでしょうか、その変更による連動が可視にすべてのスレッド?
ない場合、どうすればよいですかすべてのスレッドの同期、変数?
編集:誰から利用させていただきたいと思い利用激しい動きを示している。しかしセットの"カウンター"として揮発性のあるコンパイラの警告"参照の揮発分野として扱われるものではない揮発性".
それを読み直してみるとき"オンラインヘルプでは、"揮発性分野は通常、渡された使用またはref出力パラメータ".
解決
InterlockedIncrement /デクリメントのx86 CPU上(のx86のロック/ 12月の追加)、自動的にすべてのスレッド(すなわちへの可視性を提供します。のメモリバリアのを作成している、すべてのスレッドは、シーケンシャルのように、インオーダーとその更新を見ることができますメモリ一貫性)。メモリバリアは、保留中のすべてのメモリロード/ストアが完了することになります。 C#とJavaの(およびいくつかのC / C ++コンパイラ)はメモリバリアを作るためにvolatile
を強制するが、volatile
はこの質問とは関係ありません。しかし、連動操作がすでにCPUでメモリバリアがあります。
もルック stackoverflowのインチ
私は、x86のロックに固有のマッピングは/デクを追加しているC#のInterlockedIncrement /デクリメントすることを前提としていることに注意します。
他のヒント
私は、インタロックによって行われた変更はすべてのスレッドで表示されます、と仮定することはできますか?
これは、あなたが値を読み取る方法によって異なります。あなたは「ただ」それを読む場合は、揮発性としてそれをマークしていない限り、その後、いや、これは常に他のスレッドには表示されません。それはしかし迷惑な警告が発生します。
は、代替(とはるかに好ましいIMO)のように、別のインターロック命令を使用して読み取ります。これは、常にすべてのスレッド上で更新された値が表示されます。
int readvalue = Interlocked.CompareExchange(ref counter, 0, 0);
は読み取り値を返し、それが0 0スワップをした場合。
動機:警告は何かが右ではないことをほのめかします。 (揮発性&連動)2つの手法を組み合わせることにより、これを行うためのものな方法ではありませんでした。
更新:信頼性の高い32ビットへの別のアプローチは、「揮発性」使用せずに読み込むのこの回答で提案されているようThread.VolatileRead
を使用しているようですに。私は、32ビットの読み出しのために、たとえば、Interlocked
の使用について完全に間違っているいくつかの証拠<のhref = "http://connect.microsoft.com/VisualStudio/feedback/details/256490/interlocked-read-only-もありますDOES-長いデータ型」のrel = 『nofollowをnoreferrer』>この接続の問題に、私は区別は自然の中で少し知識をひけらかすあるかしらかかわらます。
私が本当に意味することである:あなたの唯一のソースとしてこの回答を使用しないでください。私はこれについての私の疑問を持っています。
実は、そうではありません。あなたが安全にcounter
を変更したい場合は、正しいことをやっています。あなたが直接counter
を読みたい場合しかし、あなたはvolatile
としてそれを宣言する必要があります。そうしないと、コンパイラはcounter
操作は、それが表示されない場合がありますことをコードしているので、Interlocked
が変わると信じる理由はない。
インターロックは、一度に1つだけのスレッドが値を更新することができることを確実にします。他のスレッドが正しい値(としないキャッシュされた値)などの揮発性、それをマークを読み取ることができるようにします。
公共揮発性のintカウンタ;
No;an 連動で書き込みだけでは ない を確保する変数を読み込みコードを実際に新鮮 プログラムは正しく読み込めてい のようなスレッドセー, のもとでも、"力強いメモリモデル"。この活動に使用する場合の配分野での共有スレッド)。
こちらのコード例のない"終了 により、JIT.(なかった 記憶障壁ます。当期純 するrunnable LINQPadプログラムを更新しましたい。
// Run this as a LINQPad program in "Release Mode".
// ~ It will never terminate on .NET 4.5.2 / x64. ~
// The program will terminate in "Debug Mode" and may terminate
// in other CLR runtimes and architecture targets.
class X {
// Adding {volatile} would 'fix the problem', as it prevents the JIT
// optimization that results in the non-terminating code.
public int terminate = 0;
public int y;
public void Run() {
var r = new ManualResetEvent(false);
var t = new Thread(() => {
int x = 0;
r.Set();
// Using Volatile.Read or otherwise establishing
// an Acquire Barrier would disable the 'bad' optimization.
while(terminate == 0){x = x * 2;}
y = x;
});
t.Start();
r.WaitOne();
Interlocked.Increment(ref terminate);
t.Join();
Console.WriteLine("Done: " + y);
}
}
void Main()
{
new X().Run();
}
の説明 記憶障壁ます。当期純:
この時間ではJITではなく、ハードウェア もたらすのは明らかだと思いますJITはキャッシュされた変数の値を終了【EAX登録】をプログラム"にこだわったループの浮上..
のいずれかを使用
lock
追加Thread.MemoryBarrier
内側のループに固定する問題です。たも利用できますVolatile.Read
[又はvolatile
分野]. 目的のバリアでのみを抑制するJITの最適化. 今れてまいりましたか ソフトウェア及びハードウェアが並べ替えのメモリ事業, で議論する時間を割ける記憶障壁..
この追加 バリア の構築が必要になりますので、読み手側に 防止の問題作成-JIT再順序付け/最適化: このというのは別の問題以上のメモリヒ!
追加 volatile
このよう 防止 のJITの最適化、およびこのように'fixの問題は、それらが結果に表示されます。このプログラムでの修正を通じての利用 Volatile.Read
または、その他様々な業務の原因となる障壁:これらの障壁として多くのCLR/JITプログラムの正確性、裏付けハードウェアメモリ柵.