在std::atomic<T>::exchange的例子中,为什么次数不是25?

Pei*_*pei 0 c++ atomic stdatomic

我谈到的例子是cppreference.com 上的这个例子。代码片段粘贴在下面。

int main(){
    const std::size_t ThreadNumber = 5;
    const int Sum = 5;
    std::atomic<int> atom{0};
    std::atomic<int> counter{0};
 
    // lambda as thread proc
    auto lambda = [&](const int id){
        for (int next = 0; next < Sum;){
            // each thread is writing a value from its own knowledge
            const int current = atom.exchange(next);
            counter++;
            // sync writing to prevent from interrupting by other threads
            std::osyncstream(std::cout)
                << '#' << id << " (" << std::this_thread::get_id()
                << ") wrote " << next << " replacing the old value "
                << current << '\n';
            next = std::max(current, next) + 1;
        }
    };
 
    std::vector<std::thread> v;
    for (std::size_t i = 0; i < ThreadNumber; ++i){
        v.emplace_back(lambda, i);
    }
 
    for (auto& tr : v){
        tr.join();
    }
 
    std::cout << ThreadNumber << " threads adding 0 to "
              << Sum << " takes total "
              << counter << " times\n";
}
Run Code Online (Sandbox Code Playgroud)

对我来说, 的值为counter25,因为有 5 个线程,每个线程循环 5 次。然而,显示的输出是 16。我自己也运行了它,可能的值有所不同,但它永远不会是 25。

为什么计数器的打印值实际上更小?

Hol*_*Cat 7

考虑一种可能的执行方式:

假设其中一个线程在其他线程开始之前完成循环。

这给了你atom == 4。下一个进入循环的线程将获得current == 4并将在第一次迭代后退出循环。

这样,第二个线程就会递增current一次,而不是像您期望的那样递增 5 次。