Race ConditionとInterlocked
10182 ワード
正式に説明する前に、次のコードをチェックします.
もちろん数はゼロに割り当てられるべきだと思います.
しかし、結果はまったく予想外の結果になった.
このような現象の原因は競争条件である.
Race Conditionとは?
マルチスレッド環境では、2つの命令が同じメモリに同時にアクセスすると、それらの競合により実行結果が予知できなくなります.
あなたがもっと理解しやすいように、レストランの角度から説明します.
レストランからコーラを注文されると、従業員たちは競争します.
客(利用者)に複数のコーラをもたらす現象と理解すれば容易である.
つまり,スレッド間の競合により実行結果を予測することができない.
コードをよく見てみましょう.
したがって,マルチスレッド環境では,上記6行のコードが同時に実行され,結果の予測が不可能になる.
これらの問題を解決するには、原子性を保証すればいい.
原子性とは何ですか.再分割不可能な性質で、実行時に常に完全に行われて終了したり、実行不可能な場合に実行しない場合を指す.
すなわち,number++とnumber--演算は原子性を保証し,一度に実行したり,いっそ実行したりすることを避けることができる.
修正コードは次のとおりです.
1つのロックが実行されると、もう1つのロックが待機されます.
このように、多発的な競争を同時に行えば、最終的な勝者だけが仕事を行い、結果が保障される.
しかし、仕事のスピードはもちろん元の演算より遅い.1つのジョブが終わるまで、他のジョブは待たなければならないからです.
番外、numberという値を抽出したい場合は、どうすればいいですか?
prev=numberのようにnumber(Load)を抽出する演算では他のスレッドからnumberにアクセスできるため予測不可能な結果が生じる.
class Program
{
static int number = 0;
static void Thread_1()
{
for(int i=0; i<100000; i++)
{
number++;
}
}
static void Thread_2()
{
for(int i=0; i<100000; i++)
{
number--;
}
}
static void Main(string[] args)
{
Task t1 = new Task(Thread_1);
Task t2 = new Task(Thread_2);
t1.Start();
t2.Start();
Task.WaitAll(t1, t2);
Console.WriteLine(number);
}
}
numberプラス1の演算を10万回、numberプラス1の演算を10万回行う.もちろん数はゼロに割り当てられるべきだと思います.
しかし、結果はまったく予想外の結果になった.
このような現象の原因は競争条件である.
Race Conditionとは?
マルチスレッド環境では、2つの命令が同じメモリに同時にアクセスすると、それらの競合により実行結果が予知できなくなります.
あなたがもっと理解しやすいように、レストランの角度から説明します.
レストランからコーラを注文されると、従業員たちは競争します.
客(利用者)に複数のコーラをもたらす現象と理解すれば容易である.
つまり,スレッド間の競合により実行結果を予測することができない.
コードをよく見てみましょう.
number++;
number--;
2つのコードは、コンポーネント言語の観点から以下のように説明できます.int temp = number;
temp += 1;
number = temp;
int temp = number;
temp -= 1;
number = temp;
number++とnumber--コードは、3つの演算で動作するコードです.したがって,マルチスレッド環境では,上記6行のコードが同時に実行され,結果の予測が不可能になる.
これらの問題を解決するには、原子性を保証すればいい.
原子性とは何ですか.再分割不可能な性質で、実行時に常に完全に行われて終了したり、実行不可能な場合に実行しない場合を指す.
すなわち,number++とnumber--演算は原子性を保証し,一度に実行したり,いっそ実行したりすることを避けることができる.
修正コードは次のとおりです.
static void Thread_1()
{
for(int i=0; i<100000; i++)
{
Interlocked.Increment(ref number);
}
}
static void Thread_2()
{
for(int i=0; i<100000; i++)
{
Interlocked.Decrement(ref number);
}
}
ロックシリーズはAllor Nothingです.すなわち、実行または実行しない.1つのロックが実行されると、もう1つのロックが待機されます.
このように、多発的な競争を同時に行えば、最終的な勝者だけが仕事を行い、結果が保障される.
しかし、仕事のスピードはもちろん元の演算より遅い.1つのジョブが終わるまで、他のジョブは待たなければならないからです.
番外、numberという値を抽出したい場合は、どうすればいいですか?
for(int i=0; i<100000; i++)
{
prev = number;
Interlocked.Increment(ref number);
next = number;
}
そうするのはもちろんだめだ.prev=numberのようにnumber(Load)を抽出する演算では他のスレッドからnumberにアクセスできるため予測不可能な結果が生じる.
int afterValue = Interlocked.Increment(ref number);
上記のコードに示すように,反発関数の戻り値からnumberの値を抽出しなければならない.Reference
この問題について(Race ConditionとInterlocked), 我々は、より多くの情報をここで見つけました https://velog.io/@kkuoo7/Race-Condition과-Interlockedテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol