2012-06-19 2 views
5

가능한 중복 :
C# Captured Variable In Loop간단한 스레딩

내가 스레딩의 몇 가지 간단한 응용 프로그램에서 일하고 있어요,하지만 난이 작업을 얻이 수없는 것 :

class ThreadTest 
{ 
    static Queue<Thread> threadQueue = new Queue<Thread>(); 

    static void Main() 
    { 
     //Create and enqueue threads 
     for (int x = 0; x < 2; x++) 
     { 
      threadQueue.Enqueue(new Thread(() => WriteNumber(x))); 
     } 

     while(threadQueue.Count != 0) 
     { 
      Thread temp = threadQueue.Dequeue(); 
      temp.Start(); 
     } 

     Console.Read(); 
    } 

    static void WriteNumber(int number) 
    { 
     for (int i = 0; i < 1000; i++) 
     { 
      Console.Write(number); 
     } 
    } 
} 

목표는 기본적으로 하나씩 대기열에 스레드를 추가 한 다음 대기열을 차례로 이동하여 튕기는 것입니다 스레드를 실행하고 실행하십시오. 때문에 "x < 2"내 루프에, 그것은 단지 두 개의 스레드를 만들어야합니다 - 하나 WriteNumber (0)을 실행하고 WriteNumber (1)을 실행합니다. 스레드가 궁극적으로 실행되는 방식에 따라 다양한 순서로 1000 1이 내 화면에 나타납니다.

나는 결국 2000 2가된다. 두 가지 가능한 해결책은 다음과 같습니다. 나는 눈에 띄게 눈에 띄지 않는 것을 놓쳤습니다. WriteNumber 함수에 변수 x를 보내면 참조에 의한 통과가 아닌 값에 의한 전달이 수행되므로, 스레드는 함수가 설정된 시점의 최신 버전 대신 최신 버전의 x를 사용하고 있습니다. 그러나 변수는 기본적으로 C#에서 값으로 전달되며 매개 변수에 'ref'를 포함하면 참조로 전달됩니다.

+2

스레드 대기열은 확실히 이상한 아이디어입니다. – CodesInChaos

+0

스레드 풀이 내부적으로하는 일은 생각만큼 쉽지 않습니다. 그래서 threadpool instad를 사용하십시오. – DarthVader

+0

Threadpools에는 일반적으로 작업 클래스 인스턴스의 대기열이 있으며, 추적 할 수있는 경우 작업을 대기열에서 제외하고 실행하는 고정 된 스레드 목록이 있습니다. 목록/대기열의 스레드를 미세 조정하면 대개 재앙이 발생합니다. 나는 목록에서 쓰레드가 '끝났다'면 폴링을 시도하는 코드의 큰 덩어리에 대한 몇 가지 시도를 보았고, 그것들을 해제하고 배열에서 구멍을 채우기 위해 새로운 것을 시도했다. 정말 끔찍한 ... –

답변

18

람다 식에서 x을 캡처 중입니다. 스레드를 시작하기 전에 x의 값이 2로 변경됩니다.

for (int x = 0; x < 2; x++) 
{ 
    int copy = x; 
    threadQueue.Enqueue(new Thread(() => WriteNumber(copy))); 
} 

람다 표현식은 변수를 캡처 : 당신은 내에서 루프를 값 의 복사본을 만들 필요가있다. 값이 값에 의해 전달 WriteNumber입니다에 전달하더라도, 스레드가 시작될 때 모든 때까지에서 호출 아니에요 -하는 시간 x는 루프 내에서 복사를 2.

이다, 루프의 각 반복 가져 copy 변수의 자체 별개의 인스턴스이고 이 값을 변경하지 않으므로 ... WriteNumber이 호출 될 때마다 각 copy 변수는 여전히 해당 값의 반복에 대해 x과 동일한 값을 갖습니다.

+0

매혹적인, 고마워요! 나는 람다 표현에 할 연구가 1 톤 더있는 것처럼 보입니다! – Jake

9

x 값은 이후에 에 액세스하므로이 시간은 2입니다.

가변 캡처를 방지하려면 임시 변수를 사용해야합니다.

for (int x = 0; x < 2; x++) 
{ 
    int tmp = x; 
    threadQueue.Enqueue(new Thread(() => WriteNumber(tmp))); 
}