この質問では、競合状態やロックの必要性とは関係なく、C# スレッド動作の潜在的な異常について調査します。具体的には、スレッドが値をキャッシュし、他のスレッドでその値に加えられた変更を無視できるかどうかが問題となり、予期せぬ動作につながる可能性があります。
NET ランタイムがメモリを管理することで、この問題が軽減されると考えられています。しかし、一部の文献ではそうではないと主張し、次のような特定のコード構造が無限ループにつながる可能性があると主張しています。
class BackgroundTaskDemo { private bool stopping = false; static void Main() { BackgroundTaskDemo demo = new BackgroundTaskDemo(); new Thread(demo.DoWork).Start(); Thread.Sleep(5000); demo.stopping = true; } static void DoWork() { while (!stopping) { // Do something here } } }
参照された記事によると (http://www.yoda.arachsys.com/) csharp/threads/volatility.shtml 、 http://softwareengineering.stackexchange.com/questions/104757/is-a-string-property-itself-threadsafe)、読み取りスレッドが停止変数の初期値をキャッシュし、それ以降のすべての更新が非表示になり、スレッドが
しかし、メモリ モデリングの専門家は、そのような動作は C# 仕様では保証されていないと主張しています。提供されたコードは通常は正しく機能しますが、具体的な言語セマンティクスではなく、プラットフォームおよびコンパイラ固有の最適化に依存しています。
問題をさらに詳しく説明するには、次の変更されたコードを考慮してください。
using System.Threading; using System; static class BackgroundTaskDemo { //make this volatile to fix it private static bool stopping = false; static void Main() { new Thread(DoWork).Start(); Thread.Sleep(5000); stopping = true; Console.WriteLine("Main exit"); Console.ReadLine(); } static void DoWork() { int i = 0; while (!stopping) { i++; } Console.WriteLine("DoWork exit " + i); } }
この変更により、コードは予想通り「Main exit」を出力しますが、DoWork メソッドは無期限に実行され続けます。この反例は、最初の疑念にもかかわらず、C# ランタイムがスレッド間での値の更新の一貫性を常に保証するとは限らないことを示しています。
この曖昧さを解決するには、volatile キーワードを停止変数に適用できます。 volatile 修飾子は変数へのアトミック アクセスを強制し、キャッシュされた値によって実際の更新がわかりにくくなるのを防ぎます。
以上がC# スレッドは他のスレッドからの値の変更を無視できますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。