C# ラムダ式と foreach
ループ スレッド セーフティ
この記事では、C# ラムダ式内の foreach
ループ内の変数にアクセスする場合のスレッド セーフについて、C# バージョン間の違いに焦点を当てて検証します。
C# 5 以前の動作
5 より前の C# バージョンでは、マルチスレッド コンテキスト (foreach
コンストラクター内など) で使用されるラムダ式内の Thread
ループの外側で宣言された変数に直接アクセスすることは、安全ではありません。 これは、foreach
ループの反復子変数がすべての反復で共有されるためです。 その結果、複数のスレッドが同じ変数にアクセスして変更する可能性があり、予測できない不正確な結果が生じる可能性があります。 競合状態が発生する可能性が非常に高くなります。
C# 5 以降
C# 5 以降、コンパイラによる foreach
ループ内の反復子の処理により、スレッドの安全性が大幅に向上します。 コンパイラは、反復ごとにイテレータ変数の新しいインスタンスを効果的に作成するようになりました。 これは、各ラムダ式が変数の一意のコピーをキャプチャし、競合状態のリスクを排除することを意味します。 したがって、C# 5 以降のバージョンでは、どちらのアプローチ (ループの外側または内側で宣言された単一の反復子変数を使用する) も一般にスレッドセーフとみなされます。
例 (C#5 以前の安全でない動作)
次のコード スニペットは、C#5 より前のバージョンでの安全でない動作を強調しています:
<code class="language-csharp">static void Main() { int[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; foreach (int i in data) { new Thread(() => Console.WriteLine(i)).Start(); } Console.ReadLine(); }</code>
の値が順番に正しくない出力が生成される可能性があり、競合状態が示されます。各スレッドは同じ i
変数をキャプチャし、スレッドがラムダ式を実行するまでにその値が変わる可能性があります。i
結論
古い C# バージョンでは、スレッド セーフを確保するためにラムダ式内の ループで反復子変数を慎重に処理する必要がありましたが、C# 5 以降のバージョンでは、コンパイラの最適化によってこの問題が軽減されています。 ただし、C# のバージョンに関係なく、特にラムダ式内の共有リソースを扱う場合には、潜在的な同時実行の問題に留意することをお勧めします。 各反復内でローカル変数を使用することは、明確さと保守性を確保するためのベスト プラクティスです。foreach
以上がC# ラムダ式内の Foreach ループ内の変数へのアクセスはスレッドセーフですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。