2011-02-08 6 views
1

비슷한 질문을 here에게 묻지 만 일반적으로 대답은 모두 람다 표기법과 관련이있는 것 같습니다.스레드 시작을위한 경쟁 조건

Thread 0 
Thread 1 
Thread 2 
Thread 3 
Thread 4 
:

for (int i = 0; i < 5; i++) 
    (new Thread(new ThreadStart(delegate() 
    { 
     Console.WriteLine("Thread " + i); 
    }))).Start(); 

하나는 다음과 같은 출력을 기대 :

나는 이런 식으로 뭔가를 말 : 나는 람다없이 비슷한 결과가 그래서 내가 어떤 해명을 요구라고 생각 얻을

이제 스레드가 특정 순서로 시작되지 않는다는 것을 알았으므로 위의 행이 어떤 순서로든 나올 수 있다고 가정 해 봅시다.

그러나 그런 일은 발생하지 않습니다. 대신에 어떻게됩니까 : 믿는 것이 아니라 내가,이 기준을 통과하면 값을 전달하는 날 리드 유사한

Thread 3 
Thread 4 
Thread 4 
Thread 4 
Thread 4 

또는 무언가를. (int가 값 유형이기 때문에 이상하게 보입니다.) 이 같은

이렇게 뭔가 :

for (int i = 0; i < 5; i++) 
    (new Thread(new ThreadStart(delegate() 
    { 
     int j = i; 
     Console.WriteLine("Thread " + j); 
    }))).Start(); 

우리가 내가 사본을 만든 경우에도, 도움이되지 않습니다. 그 이유는 내가 시간의 사본을 만들지 못했다는 것입니다. 이 같은

이렇게 뭔가 :

for (int i = 0; i < 5; i++) 
{ 
    (new Thread(new ThreadStart(delegate() 
    { 
     Console.WriteLine("Thread " + i); 
    }))).Start(); 
    Thread.Sleep(50); 
} 

우리가 반복 될 때마다 50ms가 낭비하고 그러나이 사실을 언급하지 않기 위하여, 매우 바람직하지 않다, 문제를 해결하는 것 같다 컴퓨터가 크게 다음로드 된 경우 그 어쩌면 50ms 정도면 충분하지 않을 수도 있습니다.

Thread t = new Thread(new ThreadStart(delgate() 
    { 
    threadLogic(param1, param2, param3, param4); 
    })); 
t.Start(); 

param1 = param2 = param3 = param4 = null; 

과 : 여기

는 나의 현재, 특정 문제에 샘플입니다 내가 threadLogic()가 자신의 스레드에서 실행하려는

void threadLogic(object param1, object param2, object param3, object param4) 
{ 
    // Do some stuff here... 
} 

그러나 위의 코드는 널 (null)을 제공 참조 예외. 스레드가 시작될 수 있기 전에 값이 null로 설정되어 있기 때문입니다.

다시 한번 Thread.Sleep (100)을 넣는 것은 모든면에서 끔찍한 해결책입니다. 당신은이 특별한 유형의 경쟁 조건을 위해 무엇을 추천합니까?

+0

참조를 http://stackoverflow.com/questions/1930133/c-closures-why-is-the-loopvariable-captured-by-reference 및 http://stackoverflow.com/ 질문/1923577/differing-behaviour-when-starting-a-thread-parameterized 스레드 시작 - 익명/ – nos

답변

3

당신은 임시을 소개해야합니다

for (int i = 0; i < 5; i++) 
{ 
    int temp = i; // Add this 
    (new Thread(new ThreadStart(delegate() 
    { 
     Console.WriteLine("Thread " + temp); 
    }))).Start(); 
} 

문제에 어떻게 (내에서 코드에서 i, temp) 외부 변수 주위에 가까운 위임한다. 범위가 잘못되었습니다 (for 루프 외부). 스레드가 시작될 때까지 i이 이미 모두 증가하지는 않았지만 이미 증가했습니다.


두 번째 예도 똑같이해야합니다. 그냥 임시직합니다

var temp1 = param1; 
var temp2 = param2; 
var temp3 = param3; 
var temp4 = param4; 
Thread t = new Thread(new ThreadStart(delgate() 
    { 
    threadLogic(temp1, temp2, temp3, temp4); 
    })); 
t.Start(); 

// This is now safe, since the closure above is over "temp*" 
param1 = param2 = param3 = param4 = null; 
+0

고마워, 내가 준 간단한 예제를위한 훌륭한 솔루션이다. 스레드 매개 변수가 t.Start() 바로 다음에 null로 설정되는 다른 문제는 어떻습니까? – Ozzah

+0

@Ozzah : 매개 변수를 임시로 복사하면됩니다. 그렇게하면 임시 변수 (실제 변수가 아닌)가 닫히고 적절한 값이됩니다. –

+0

@Ozzah : 사례 2를 해결하는 방법을 보여주기 위해 내 대답을 수정했습니다. –

3

문제는 동일합니다. 람다 구문 자체가 아니기 때문에 익명 메소드로 지역 변수를 닫는 것이 사실입니다 (사용중인 delegate 구문은 .NET 2.0에서 데뷔 한 익명 메소드의 첫 번째 반복 구문입니다). 이 작업을 수행하려면

, 당신은 당신이 해결 사용해야합니다 : 이것은 당신이 (복사) 시도 것과 유사하다

for (int i = 0; i < 5; i++) 
{ 
    int j = i; 
    (new Thread(new ThreadStart(delegate() 
    { 
     Console.WriteLine("Thread " + j); 
    }))).Start(); 
} 

참고하지만, 외부의을 할 필요가 폐쇄 및 내부에 루프. 익명의 함수 내에서 복사하는 것은 도움이되지 않습니다.

관련 문제