'Instance'を介した'Toggle()'クラスへのアクセスはスレッドセーフですか?はいの場合、どのような仮定、規則などによって。いいえの場合、なぜ、どのように修正できますか?
いいえ、スレッドセーフではありません。
基本的に、両方のスレッドがToggle
同時に関数を実行できるため、これが発生する可能性があります
// thread 1 is running this code
if(value == 0)
{
value = 1;
// RIGHT NOW, thread 2 steps in.
// It sees value as 1, so runs the other branch, and changes it to 0
// This causes your method to return 0 even though you actually want 1
}
else if(value == 1)
{
value = 0;
}
return value;
次の仮定で操作する必要があります。
2つのスレッドが実行されている場合、それらは任意の時点でランダムにインターリーブし、相互作用します。64ビット整数またはfloat(32ビットCPUの場合)の書き込みまたは読み取りの途中で、別のスレッドがジャンプして下から変更することができます。
2つのスレッドが共通点にアクセスしない場合は問題ありませんが、アクセスしたらすぐに、お互いのつま先を踏まないようにする必要があります。.NETでこれを行う方法は、ロックを使用することです。
次のようなことを考えると、何をどこでロックするかを決めることができます。
与えられたコードのブロックについて、の値がsomething
私の下から変更された場合、それは重要ですか?もしそうなら、something
それが問題になるコードの期間中、それをロックする必要があります。
あなたの例をもう一度見てください
// we read value here
if(value == 0)
{
value = 1;
}
else if(value == 1)
{
value = 0;
}
// and we return it here
return value;
これが期待どおりの結果を返すためにvalue
、読み取りと。の間で変更されないことを前提としていreturn
ます。この仮定が実際に正しいためにvalue
は、そのコードブロックの期間中ロックする必要があります。
だからあなたはこれをするでしょう:
lock( value )
{
if(value == 0)
... // all your code here
return value;
}
でも
.NETでは、参照型のみをロックできます。Int32は値型であるため、ロックすることはできません。
これを解決するには、「ダミー」オブジェクトを導入し、 「値」をロックしたい場所でそれをロックします。
これはBenScheirmanが言及しているものです。