运行时线程数未知时,如何创建std::barrier屏障对象?
运行时构造std::barrier的几种实用方案
直接在计数确定后构造
先通过运行时逻辑(比如读取配置、计算CPU核心数、根据任务量推导)拿到线程数,紧接着构造屏障,再基于它启动线程即可,这是最直接的方式:
#include <barrier> #include <thread> #include <vector> int main() { // 模拟运行时确定线程数——比如从外部配置读取或动态计算 size_t thread_count = std::thread::hardware_concurrency(); // 线程数确定后,直接构造屏障 std::barrier my_barrier(thread_count); std::vector<std::thread> threads; threads.reserve(thread_count); for (size_t i = 0; i < thread_count; ++i) { threads.emplace_back([&my_barrier, i]() { // 线程先等待屏障同步 my_barrier.arrive_and_wait(); // 执行后续任务逻辑 // ... }); } for (auto& t : threads) { t.join(); } return 0; }
用智能指针延迟分配
如果屏障需要属于某个类成员,或者不能在函数开头就确定构造时机,可以用std::unique_ptr动态创建,避免提前占用资源:
#include <barrier> #include <thread> #include <vector> #include <memory> class TaskCoordinator { private: std::unique_ptr<std::barrier> sync_barrier_; std::vector<std::thread> worker_threads_; public: void start_workers(size_t thread_count) { // 运行时拿到计数后,动态初始化屏障 sync_barrier_ = std::make_unique<std::barrier>(thread_count); worker_threads_.reserve(thread_count); for (size_t i = 0; i < thread_count; ++i) { worker_threads_.emplace_back([this]() { this->sync_barrier_->arrive_and_wait(); // 执行工作任务 // ... }); } } void wait_workers_done() { for (auto& t : worker_threads_) { t.join(); } } }; int main() { TaskCoordinator coord; // 模拟运行时确定线程数 size_t target_count = 4; coord.start_workers(target_count); coord.wait_workers_done(); return 0; }
用std::optional实现栈上延迟构造
如果不想用动态内存分配,可以用std::optional把屏障存在栈上,等计数确定后再初始化:
#include <barrier> #include <thread> #include <vector> #include <optional> int main() { std::optional<std::barrier> barrier_opt; // 运行时确定线程数 size_t thread_count = 6; // 初始化optional中的屏障对象 barrier_opt.emplace(thread_count); std::vector<std::thread> threads; for (size_t i = 0; i < thread_count; ++i) { threads.emplace_back([&barrier_opt]() { // 确保屏障已完成初始化(实际逻辑中可根据场景省略判断) if (barrier_opt) { barrier_opt->arrive_and_wait(); } // 任务代码 // ... }); } for (auto& t : threads) { t.join(); } return 0; }
注意事项
- 务必保证所有线程访问屏障之前,屏障已经完成构造,否则会触发未定义行为。
- 如果用异步启动方式(比如
std::async),同样要确保屏障初始化完成后,再让线程进入等待逻辑。
内容的提问来源于stack exchange,提问作者geenweb
相关产品推荐
相关产品推荐

