为什么我的原子操作以意想不到的顺序发生?

Col*_*nee 0 c++ windows winapi multithreading atomic

我不明白为什么会这样.拿下以下的伪代码:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在程序的第一次运行时i = 0,sum主线程的原子交换通常生成的线程完成发生.操作count总是以正确的顺序发生.

这只发生一次; 它以正确的顺序为循环的其余部分执行操作.它并不总是发生,但它通常会发生.如果我在原子添加之前进入调试器或睡眠,则指令将以正确的顺序执行.

无论哪种方式,结果是线程写入的值被替换为在线程被启动之前应该发生的0.

为什么会这样?为什么我不能依靠处理器完成我按照我给它们的顺序给出的原子指令?原子操作是否意味着阻止重新排序的内存屏障?

注意,这是在Visual Studio 2010中发生的.我没有其他版本可供测试.

pax*_*blo 7

原子操作在某种意义上是原子操作,它是不可中断的.如果没有另一个线程获得查看,它将无法执行或完全完成.

这并不意味着二十个原子操作总是以相同的顺序发生,这仍然受到多线程变幻莫测的影响.

根据线程的启动速度,它们可能被排序为main, thrd1, main, thrd2, main, thrd3, ...或者main, main, main, main, thrd1, main, main, thrd2, ...任何其他组合(尽管我很确定main总是首先只是因为它的原子操作是在启动任何线程之前).