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

将boost::barrier移植到C++20 std::barrier时遇死锁问题求解

C++20 std::barrier 移植死锁问题解决指南

核心差异:std::barrier vs boost::barrier

两者最关键的区别在于屏障重置机制:

  • boost::barrier:当所有线程调用wait()后,屏障自动重置,可直接重复使用。
  • std::barrier:当所有参与者到达后,执行完成回调(默认空),屏障进入完成状态,必须手动调用reset()才能再次使用。

你的死锁问题大概率是因为移植时没有处理这个差异,以下是针对不同场景的修正方案:


场景1:单次线程同步(仅一次汇合)

原boost代码逻辑

9个工作线程完成计算后,主线程汇总结果输出。

#include <boost/thread/barrier.hpp>
#include <thread>
#include <vector>
#include <iostream>

boost::barrier barrier(9);
int bags_of_chips = 0;

void worker() {
    bags_of_chips += 15;
    barrier.wait();
}

int main() {
    std::vector<std::thread> threads;
    for (int i = 0; i < 9; ++i) {
        threads.emplace_back(worker);
    }

    for (auto& t : threads) t.join();
    std::cout << "We need to buy " << bags_of_chips << " bags_of_chips." << std::endl;
    return 0;
}

移植后的std::barrier代码

无需主线程参与屏障,直接等待线程完成即可,不会死锁:

#include <barrier>
#include <thread>
#include <vector>
#include <iostream>

std::barrier barrier(9);
int bags_of_chips = 0;

void worker() {
    bags_of_chips += 15;
    barrier.arrive_and_wait();
}

int main() {
    std::vector<std::thread> threads;
    for (int i = 0; i < 9; ++i) {
        threads.emplace_back(worker);
    }

    for (auto& t : threads) t.join();
    std::cout << "We need to buy " << bags_of_chips << " bags_of_chips." << std::endl;
    return 0;
}

场景2:多次线程同步(重复使用屏障)

原boost代码逻辑

线程多次执行任务,每次任务后汇合(boost自动重置屏障)。

#include <boost/thread/barrier.hpp>
#include <thread>
#include <vector>
#include <iostream>

boost::barrier barrier(10); // 9线程 + 主线程
int bags_of_chips = 0;

void worker() {
    for (int i = 0; i < 9; ++i) {
        bags_of_chips += 1;
        barrier.wait();
    }
}

int main() {
    std::vector<std::thread> threads;
    for (int i = 0; i < 9; ++i) {
        threads.emplace_back(worker);
    }

    for (int i = 0; i < 9; ++i) {
        barrier.wait();
    }

    std::cout << "We need to buy " << bags_of_chips << " bags_of_chips." << std::endl;
    for (auto& t : threads) t.join();
    return 0;
}

移植后的std::barrier代码

必须在每次阶段完成后调用reset(),才能再次使用屏障:

#include <barrier>
#include <thread>
#include <vector>
#include <iostream>

std::barrier barrier(10); // 初始10个参与者
int bags_of_chips = 0;

void worker() {
    for (int i = 0; i < 9; ++i) {
        bags_of_chips += 1;
        barrier.arrive_and_wait();
    }
}

int main() {
    std::vector<std::thread> threads;
    for (int i = 0; i < 9; ++i) {
        threads.emplace_back(worker);
    }

    for (int i = 0; i < 9; ++i) {
        barrier.arrive_and_wait(); // 主线程到达,触发阶段完成
        barrier.reset(); // 重置屏障,准备下一次同步
    }

    std::cout << "We need to buy " << bags_of_chips << " bags_of_chips." << std::endl;
    for (auto& t : threads) t.join();
    return 0;
}

常见错误总结

  1. 参与者数量不匹配:如果主线程需要参与同步,构造std::barrier时必须把主线程算入数量,否则会导致部分线程永久阻塞。
  2. 未重置屏障就重复使用:std::barrier不会自动重置,多次使用必须手动调用reset(),否则后续arrive_and_wait()会触发死锁。
  3. 完成函数阻塞:自定义完成函数时,避免在函数内做阻塞操作,因为它由最后到达的线程执行,会延迟所有线程的唤醒。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 06:24:52