求问这个C++的并发程序?

#include<bits/stdc++.h>
using namespace std;
std::atomic<int> counter(0);

void increment() {
    for (int i = 0; i < 100000; ++i) {
        counter.store(counter.load() + 1);
    }
}

int main() 
{
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "Counter: " << counter.load() << std::endl;
    return 0;
}

为啥最后打印类似100475,100425之类的值?
我看写这个的人说会打印200000.

阅读 593
avatarAI BotBETA

这段C++并发程序的目的是通过两个线程同时增加一个原子整数counter的值,每个线程增加100,000次。然而,你观察到最终打印的值并不总是200,000,而是类似于100,475或100,425之类的值。

这种情况的发生是由于线程调度和执行顺序的不确定性。尽管你创建了两个线程t1t2来同时增加counter,但操作系统线程调度器会在何时执行哪个线程之间进行切换是不确定的。

当你使用counter.store(counter.load() + 1)来增加counter的值时,这个过程实际上不是一个原子操作。即使std::atomic<int>保证了loadstore操作的原子性,但整个增加操作(读取、增加、存储)不是原子的。

具体来说,假设t1线程读取了counter的当前值(例如100,000),然后t2线程也被调度并执行,它也读取了counter的当前值(还是100,000),然后t1t2都将其值增加1并存储回去。在这种情况下,尽管每个线程都增加了1,但counter的最终值只增加了1,而不是2。

要修复这个问题并确保counter最终的值是200,000,你可以使用std::atomicfetch_add函数,它将增加和存储操作合并为一个原子操作:

void increment() {
    for (int i = 0; i < 100000; ++i) {
        counter.fetch_add(1);
    }
}

使用fetch_add函数,每次增加操作都会作为一个原子操作执行,从而确保即使在并发环境中,counter的值也会正确地增加。

1 个回答
✓ 已被采纳

你先获取当前值,然后存入当前值+1,这之间如果有其它线程读取了 counter 的值,那么可能会重复操作。例如:

线程 1:load 345
线程 2: load 345
线程 2: store 346
线程 1: store 346

将代码修改为直接 +1 即可:

counter.fetch_add(1);
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏