将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; }
常见错误总结
- 参与者数量不匹配:如果主线程需要参与同步,构造
std::barrier时必须把主线程算入数量,否则会导致部分线程永久阻塞。 - 未重置屏障就重复使用:
std::barrier不会自动重置,多次使用必须手动调用reset(),否则后续arrive_and_wait()会触发死锁。 - 完成函数阻塞:自定义完成函数时,避免在函数内做阻塞操作,因为它由最后到达的线程执行,会延迟所有线程的唤醒。
内容的提问来源于stack exchange,提问作者Fnr
相关产品推荐
相关产品推荐

