2017-05-16 13 views
0

いくつかのスレッドから次のコードを呼び出す必要があります。ロックステートメントを使用せずにコードをスレッドに安全にする

// x is a global/member and initialized to 0 
if (Interlocked.Increment(ref x) == 2) 
{ 
    // do something only once 
} 

このコースのスレッドセーフではありません:xを実行時に最初のスレッドがxがインクリメントされた後に停止したが、評価の前にされた場合、次いで第2のスレッドの増分はそれが今2で、その後、if声明trueです。それから、最初のスレッドに戻り、ifステートメントでもtrueになります。

これは、コードをlockステートメントで囲むことで修正できます。

lockステートメントを使用せずにスレッドを安全にする方法はありますか?

+2

'Interlocked.Increment()'メソッドの戻り値が他のスレッドによって変更できないため、上記のシナリオは発生しません。 – dymanoid

+0

あなたのコードは後に 'x'に再びアクセスし、インクリメントの結果と同じであると仮定しても安全ではないかもしれませんが、ここにこの問題を示すコードは表示されていません。 –

答えて

2

はスレッドセーフではありません:xは、別のスレッドによって変更されている可能性があり、その次のことが真であるということは完全に可能です評価の前に増分されます。次に、2番目のスレッドがインクリメントし、xが2になるので、if文がtrueになります。次に、最初のスレッドに戻り、それも真であることが分かります。

これは当てはまりません。

Interlocked.Incrementはアトミック操作であり、余分なものはありません。lockが必要です。 (それ以外の点は何ですか?)

値は増分されており、増分値が得られます。後に別のインクリメントが発生しても、最初のインクリメント値はまだあります。 ifはfalseと評価されます。

あなたのコードはスレッドセーフです。

0

私はあなたが間違っていると思います。 Interlocked.Incrementからの戻り値は、増分後の値であり、評価時にはxの値ではありません。 xがした後、実行時に最初のスレッドが停止している場合ので、これは当然である

int x = 1; 
var y = Interlocked.Increment(ref x); 

if(x!=y) 
関連する問題