foreach
C# の変数とマルチスレッド クロージャ: 安全ですか?
C# で foreach
を使用してコレクションをループする場合、特にマルチスレッド環境では、反復変数のスコープと動作を理解することが重要です。
次のコード スニペットは、マルチスレッドで foreach
変数をクロージャー引数として直接使用するのが安全かどうか、および反復ごとにローカル コピーを作成する必要があるかどうかを調べます。
C# 5 より前のバージョン
C# 5 より前のバージョンでは、foreach
変数はループの外で宣言されていました。これは、単一の変数インスタンスがすべての反復で共有されることを意味します。
最初のコード スニペットを考えてみましょう:
<code class="language-csharp">foreach (Foo f in ListOfFoo) { Thread thread = new Thread(() => f.DoSomething()); threads.Add(thread); thread.Start(); }</code>
この例では、f
変数はループの反復中に作成されたすべてのスレッド間で共有されます。これにより、複数のスレッドが Foo
の異なるインスタンスのメソッドを呼び出したり、同じインスタンスのメソッドを複数回呼び出したりする可能性があるため、予測できない結果が生じる可能性があります。
このような問題を回避するには、2 番目のコード スニペットに示すように、反復ごとに f
変数のローカル コピーを作成することをお勧めします。
<code class="language-csharp">foreach (Foo f in ListOfFoo) { Foo f2 = f; Thread thread = new Thread(() => f2.DoSomething()); threads.Add(thread); thread.Start(); }</code>
C# 5 以降
C# 5 では重要な変更が導入されています。 C# 5 以降では、 変数はループ スコープ内で定義されます。これは、各反復に変数の独自のインスタンスがあることを意味します。 foreach
2 つのコード スニペットは等価で安全になります。各スレッドのクロージャースコープ内に独自の インスタンスが存在するようになり、混乱や不一致のリスクがなくなりました。 f
以上がC# マルチスレッド クロージャで「foreach」変数を直接使用するのは安全ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。