在类中使用std::unique_ptr<std::barrier<void()>>调用arrive_and_wait()编译报错
解决
std::barrier动态分配时的编译错误及实现动态修改等待线程数 错误根源分析
编译错误来自两个核心问题:
- 模板参数类型错误:你显式指定
std::barrier<void()>,其中void()是原始函数类型,而std::barrier的模板参数要求是可存储的可调用对象类型,直接用函数类型会导致编译器无法正确存储完成回调(错误提示中_M_completion被声明为函数类型,不符合成员变量的定义规则)。 - 类型不匹配:带
this捕获的lambda无法隐式转换为void(*)()函数指针,而std::barrier<void()>的构造函数期望第二个参数是该类型,因此触发参数不匹配错误。
修正后的代码实现
下面的代码解决了编译问题,同时支持动态修改等待线程数:
#include <iostream> #include <barrier> #include <memory> #include <thread> #include <functional> class MyClass { public: MyClass(std::ptrdiff_t thread_count = 3) { reset_barrier(thread_count); } void run() { la_barriere->arrive_and_wait(); } // 动态重置barrier,修改需要等待的线程数 void reset_barrier(std::ptrdiff_t new_thread_count) { la_barriere = std::make_unique<std::barrier<std::function<void()>>>( new_thread_count, [this]() { callback1(); callback2(); } ); } private: void callback1() { std::cout << "callback1()\n"; } void callback2() { std::cout << "callback2()\n"; } std::unique_ptr<std::barrier<std::function<void()>>> la_barriere; }; int main() { MyClass test; std::jthread t1(&MyClass::run, &test); std::jthread t2(&MyClass::run, &test); std::jthread t3(&MyClass::run, &test); // 示例:修改线程数(注意:必须确保所有线程完成当前阶段的等待后再调用,否则会触发未定义行为) // test.reset_barrier(2); return 0; }
关键修正点说明
- 用
std::function<void()>作为模板参数:它可以容纳带捕获的lambda,完美解决类型转换问题,同时保持代码的灵活性。 - 新增
reset_barrier函数:通过重新创建std::unique_ptr包裹的std::barrier实例,实现动态修改等待线程数的需求。 - 构造函数复用初始化逻辑:调用
reset_barrier完成初始化,让代码更简洁易维护。
额外优化选项(无std::function开销)
如果不需要std::function的灵活性,希望避免其运行时开销,可以让编译器自动推导lambda的类型(C++20及以上支持):
class MyClass { public: MyClass(std::ptrdiff_t thread_count = 3) { auto completion = [this]() { callback1(); callback2(); }; la_barriere = std::make_unique<std::barrier<decltype(completion)>>(thread_count, std::move(completion)); } void run() { la_barriere->arrive_and_wait(); } void reset_barrier(std::ptrdiff_t new_thread_count) { auto completion = [this]() { callback1(); callback2(); }; la_barriere = std::make_unique<std::barrier<decltype(completion)>>(new_thread_count, std::move(completion)); } private: void callback1() { std::cout << "callback1()\n"; } void callback2() { std::cout << "callback2()\n"; } std::unique_ptr<std::barrier<decltype([this]() { callback1(); callback2(); })>> la_barriere; };
内容的提问来源于stack exchange,提问作者Ibrahima Keita
相关产品推荐
相关产品推荐

