2012-02-27 3 views
0

왜 이것이 발생하는지 이해가되지 않습니다. 사이비 코드의 다음 조각을 가지고 : 프로그램의 첫 번째 실행에내 원자 조작이 예기치 않은 순서로 발생하는 이유는 무엇입니까?

volatile unsigned long count = 0; 
volatile unsigned long sum = 0; 

void ThreadFunction() { 
    InterlockedIncrement(&count); 
    InterlockedExchangeAdd(&sum, rand()); 
} 

int main() { 
    for (int i = 0; i < 10; ++i) { 
     // This is the problematic instruction 
     InterlockedExchange(&count, 0); 
     InterlockedExchange(&sum, 0); 

     std::vector<boost::thread> threads(i); 
     for (int j = 0; j < i; ++j) 
      threads[j] = boost::thread(ThreadFunction); 

     while (count != i) 
      Sleep(0); 
    } 
} 

i = 0는 주 스레드에서 sum에 원자 교환이 일반적으로 산란 스레드가 완료 후 을 발생하는 경우. count의 작업은 항상 올바른 순서로 수행됩니다.

이것은 단 한 번 발생합니다. 루프의 나머지 부분에 대해 올바른 순서로 작업을 수행합니다. 항상 그런 것은 아니지만 일반적으로 발생합니다. 원자 추가 전에 디버거 또는 절전 모드로 들어가면 지침이 올바른 순서로 수행됩니다.

어느 쪽이든 결과적으로 스레드가 작성한 값은 스레드가 시작되기 전에 발생한 0으로 대체됩니다.

왜 이런 일이 발생합니까? 왜 제가 프로세서에 의뢰 한 순서대로 원자 명령어를 완성 할 수 있습니까? 원자 연산이 재정렬을 방지하기위한 메모리 장벽을 의미하지는 않습니까?

사이드 메모, Visual Studio 2010에서 발생합니다. 테스트 할 다른 버전이 없습니다.

+0

이 문제가 의심 스럽지만'countlock' 변수와'sum' 변수는 [InterlockedIncrement()'] (http : //) 문서의 주석에 따라'__align (32) '주석을 달아야합니다. msdn.microsoft.com/en-us/library/windows/desktop/ms683614(v=vs.85).aspx) : "Addend 매개 변수가 가리키는 변수는 32 비트 경계에 정렬되어야하며, 그렇지 않으면이 함수는 다중 프로세서 x86 시스템 및 비 x86 시스템에서 예기치 않게 작동합니다. " –

+1

"i = 0 일 때 주 스레드의 합계 원자 교환은 일반적으로 스폰 된 스레드가 완료된 후에 발생합니다."i == 0 "스레드가 생성되지 않으면 'j

+0

이 코드는 내가하고있는 일을 보여주기위한 것일뿐 컴파일하는 것이 아닙니다. 내 변수는 모두 32 비트로 정렬되어 있습니다. –

답변

7

원자 연산은 인터럽트가 발생하지 않는다는 점에서 원자 적입니다. 다른 스레드가 look-in을 얻지 않으면 실행되지 않거나 완전히 완료되지 않습니다.

20 개의 원자 연산이 항상 같은 순서로 발생한다는 의미는 아니며, 여전히 멀티 스레딩의 모호함이 있습니다. (나는 그것의 원자 작업이 어떤 스레드를 시작하기 전에이기 때문에 main 항상 먼저 것이라고 꽤 확신하지만)

은 당신의 스레드가 시작 얼마나 빨리에 따라, 그들은 main, thrd1, main, thrd2, main, thrd3, ... 또는 main, main, main, main, thrd1, main, main, thrd2, ... 또는 다른 조합으로 서열을 할 수있다.

+0

방금 ​​원자 조작을 잘못 지시했다는 것을 알았습니다. 고맙습니다. 고마워요. 내가 추가 * 후 * 증가해야합니다. –

관련 문제