2011-11-10 3 views
0

나는 포스트 감소 연산자가 원자 적이지 않다는 것을 입증해야만하는 코드 샘플 this book을 시험해 보았습니다. 코드는 LinqPad에 입력 한 것입니다.포스트 감소가 원자 적이지 않다는 것을 증명하는 ... FAIL

void Main() { 
    var count = 0; 
    do { 
    _x = 10000; 
    for (int i = 0; i < 100; i++) { 
     new Thread(Go).Start(); 
    } 
    Thread.Sleep(1000); 

    Console.WriteLine("Try "+ count); 
    count++; 
    } while (_x == 0); 
    Console.WriteLine(_x); 
} 

int _x = 10000; 
void Go() { for (int i = 0; i < 100; i++) _x--; } 

아이디어는 모든 스레드가 완료되면 걸림없이 다수의 스레드에 평행 _x을 감소시키는 것은 다른 _x 후 0의 값을 초래할 수 있다는 것이다.

제 문제는 얼마나 오랫동안 시도해도 문제가 없기 때문에 결과적으로 항상 0이됩니다. 두 개의 서로 다른 컴퓨터 (Windows 7)와 두 가지 다른 버전의 .NET에서이 코드를 실행했으며 동일한 결과를 제공합니다.

무엇이 여기에 있습니까?

+3

반복 횟수를 늘리면 스레드가 너무 빨리 끝나기 전에 다른 스레드를 돌릴 수 있습니다. 이전 스레드는 끝났으며 결코 병렬로 실행되지 않습니다. 따라서 100 대신에 100000 또는 훨씬 더 큰 것으로 계산하십시오. –

+0

@ LasseV.Karlsen 예. 그거였다. Go에서 반복 횟수를 늘렸고 첫 번째 시도에서 0이 아닌 결과를 얻었습니다. 고맙습니다. – Andris

+0

먼저 스레드를 작성한 다음 루프에서 시작하십시오. 또는 수영장을 사용하십시오. –

답변

1

Lasse V. Karlsen이 제안한대로 Go에 100000 개의 개입을 추가했습니다. 코드는 첫 번째 시도에서 예상대로 작동합니다. 또한 헨크 홀터 먼 (Henk Holterman)이 제안한 것처럼 쓰레드 생성을 루프에서 제거하고 스레드 수를 줄였습니다.

void Main() 
{ 
    var count = 0; 
    do { 
    _x = 1000000; 
    var threads = Enumerable.Range(0,10).Select (_ => new Thread(Go)).ToList(); 

    foreach (var t in threads) 
    { 
     t.Start(); 
    } 

    Thread.Sleep(1000); 
    Console.WriteLine("Try "+ count); 
    count++; 
    } while (_x == 0); 
    Console.WriteLine(_x); 
} 

int _x; 
void Go() { for (int i = 0; i < 100000; i++) _x--; } 

코드가 예상대로 작동합니다.

관련 문제