..."/> ...">
C#의 foreach
루프 및 람다 표현식의 스레드 안전성 문제
다음 코드 조각을 분석해 보겠습니다.
<code class="language-csharp">foreach (Foo f in ListOfFoo) { Thread thread = new Thread(() => f.DoSomething()); threads.Add(thread); thread.Start(); }</code>
<code class="language-csharp">foreach (Foo f in ListOfFoo) { Foo f2 = f; Thread thread = new Thread(() => f2.DoSomething()); threads.Add(thread); thread.Start(); }</code>
스레드가 생성되었을 때와 동일한 루프 반복에서 각 스레드가 Foo
인스턴스의 메서드를 호출하도록 보장하는 코드 조각은 무엇입니까?
C# 5 이상에서는 클로저 범위 내의 변수 정의에 대한 컴파일러 변경으로 인해 두 코드 조각 모두 안전합니다. 그러나 C# 5 이전에는 두 번째 코드 조각만 안전했습니다.
첫 번째 코드 조각에서 f
변수는 루프 외부에 선언되어 실행 내내 계속 표시됩니다. 이는 클로저 범위에 f
인스턴스가 하나만 있음을 의미합니다. 따라서 f
에 액세스하는 다른 스레드가 충돌하여 메서드 호출 오류가 발생할 수 있습니다.
이 문제를 완화하기 위해 두 번째 코드 조각에서는 루프 내부에 새 변수 f2
를 선언합니다. 이렇게 하면 각 클로저 범위에 Foo
인스턴스에 대한 자체 참조 복사본이 있어 스레드별 안전한 메서드 실행이 보장됩니다.
다음 예에서는 이 문제를 보여줍니다.
<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
변수를 참조하고 foreach
값이 i
루프가 끝난 후 마지막 값이기 때문입니다.
따라서 스레드 안전성을 보장하려면 두 번째 코드 조각에 표시된 대로 foreach
루프 내에서 Lambda 표현식을 사용할 때 항상 로컬 변수의 복사본을 생성하는 것이 가장 좋습니다.
위 내용은 내 'foreach' 루프와 Lambda 스레딩은 C#에서 안전합니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!