如何将带参数on_completion函数的std::barrier传入线程函数
解决C++ std::barrier完成函数访问Data对象的问题
核心思路
std::barrier的完成函数本身不支持接收参数,要让它访问外部Data对象,正确的做法是通过lambda捕获(或其他带状态的可调用对象)来获取Data的引用/指针,而非试图修改完成函数的签名。
修正后的完整代码示例
#include <barrier> #include <thread> #include <iostream> struct Data { int value = 0; }; void thread_function(Data& data, std::barrier<>& bar) { // 线程前置工作:修改Data临时值 data.value += 1; // 等待所有线程到达屏障 bar.arrive_and_wait(); // 屏障完成后的后续工作 std::cout << "线程完成屏障同步,当前data值:" << data.value << "\n"; } int main() { const int thread_count = 3; Data data; // 定义完成函数:通过引用捕获data,在屏障触发时修改对象 auto completion_func = [&data]() noexcept { data.value *= 2; // 示例操作:将data值翻倍 std::cout << "所有线程到达屏障,已更新data值为:" << data.value << "\n"; }; // 初始化barrier:C++20起可自动推导完成函数类型 std::barrier barrier(thread_count, completion_func); // 创建线程:用std::ref传递引用,避免拷贝 std::thread t1(thread_function, std::ref(data), std::ref(barrier)); std::thread t2(thread_function, std::ref(data), std::ref(barrier)); std::thread t3(thread_function, std::ref(data), std::ref(barrier)); // 等待所有线程执行完毕 t1.join(); t2.join(); t3.join(); return 0; }
关键细节说明
- 捕获外部变量:完成函数lambda通过
[&data]引用捕获Data对象,在屏障触发时直接访问并修改它,无需额外传参。 - barrier类型匹配:线程函数中的barrier参数用
std::barrier<>&(自动推导类型的引用),确保和main中定义的barrier类型一致;若需显式指定模板参数,可写为std::barrier<decltype(completion_func)>。 - 引用传递线程参数:创建线程时必须用
std::ref传递data和barrier,否则线程会拷贝对象,导致操作的是副本而非原对象。 - 生命周期保证:确保Data对象的生命周期覆盖所有线程和barrier的存在周期(示例中main函数的data直到所有线程join后才销毁,符合要求)。
内容的提问来源于stack exchange,提问作者someone12321
相关产品推荐
相关产品推荐

