You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

并行std::for_each数据竞争疑问:cppreference示例代码错误解析

为什么这个并行for_each示例是错误的?

你忽略了std::execution::par执行策略的一个关键细节:它不保证任务一定会并行执行。标准允许实现选择串行执行这些任务,而这正是导致代码死锁的核心原因。

让我们拆解两种执行场景:

场景1:你假设的并行执行(能正常运行的情况)

如果实现用两个线程分别处理数组的两个元素:

  • 线程1执行x.fetch_add(1),x变为1,接着进入while循环等待x变成2
  • 线程2执行x.fetch_add(1),x变为2,此时两个线程的循环条件都不满足,顺利退出
    这种情况下代码确实能正常运行,但这只是其中一种可能的执行路径。

场景2:串行执行(你没考虑到的致命情况)

如果实现选择串行执行两个lambda(比如系统资源不足,或者实现本身倾向于串行处理小任务):

  1. 第一个lambda执行:x.fetch_add(1)让x变成1,接着进入while (x.load() == 1)循环
  2. 此时第二个lambda还没有被执行,x的值会一直是1,这个循环会无限运行下去,直接导致程序卡死

这就是代码被标注为错误的本质:它隐含假设了任务一定会被并行执行,但par策略并没有给出这个保证。

额外补充:即使并行也有潜在问题

退一步说,就算是并行执行,线程调度的随机性也可能导致逻辑不符合预期——比如某个线程的fetch_add完成后,另一个线程还没开始执行,等待的线程会空转很久,但最致命的还是串行执行时的死锁问题。

怎么修复?

不要依赖执行策略的并行性来实现同步逻辑,改用明确的同步原语(比如std::latch或std::barrier)来协调任务:

std::atomic<int> x{0};
int a[] = {1,2};
std::latch latch(2); // 等待2个任务到达同步点

std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int) {
    x.fetch_add(1, std::memory_order_relaxed);
    latch.count_down();
    latch.wait(); // 等待所有任务完成fetch_add步骤
});

这样不管是串行还是并行执行,每个任务都会先完成fetch_add,再等待所有任务都到达同步点,彻底避免了死锁风险。


内容的提问来源于stack exchange,提问作者bartop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:26:47