如何实现仅收到退出信号终止、异常自动重启的std::thread包装类
方案优化点和改进实现
核心优化点
- 线程安全修复:原方案中
exit_requested_是普通bool类型,主线程调用signal_exit修改该值、工作线程读取该值的操作存在数据竞争,属于未定义行为,需要替换为std::atomic<bool>保证多线程访问安全。 - 降低版本依赖,兼容C++11及以上标准:不需要用类模板绑定lambda类型,改用
std::function<void()>存储任务即可,构造函数通过完美转发适配任意可调用对象和参数,使用体验和原生std::thread完全一致,无需C++17支持。 - 异常处理完善:原方案仅捕获
std::exception类型异常,若任务抛出非标准异常会直接触发程序终止,补充catch(...)捕获所有异常;同时支持自定义错误处理回调,替代固定写std::cout的硬编码逻辑。 - 接口对齐原生std::thread:补充
detach、get_id、joinable等常用接口,降低用户学习成本;新增析构函数自动处理线程退出逻辑,避免原生std::thread析构时若仍可连接直接终止程序的问题。 - 空任务防护:增加对空任务的检查,避免调用空可调用对象触发异常。
改进后完整实现
#include <thread> #include <atomic> #include <functional> #include <exception> #include <iostream> class thread_wrapper { public: // 兼容任意可调用对象和参数,和std::thread用法完全一致 template<typename Callable, typename... Args> explicit thread_wrapper(Callable&& func, Args&&... args) : task_(std::bind(std::forward<Callable>(func), std::forward<Args>(args)...)) , th_(&thread_wrapper::execute, this) {} ~thread_wrapper() { if (th_.joinable()) { signal_exit(); join(); } } void signal_exit() { exit_requested_.store(true, std::memory_order_release); } bool joinable() const noexcept { return th_.joinable(); } void join() { if (joinable()) th_.join(); } void detach() { th_.detach(); } std::thread::id get_id() const noexcept { return th_.get_id(); } std::thread::native_handle_type native_handle() { return th_.native_handle(); } // 可选:自定义异常处理回调 void set_error_handler(std::function<void(const std::exception_ptr&)> handler) { error_handler_ = std::move(handler); } private: std::thread th_; std::atomic<bool> exit_requested_{false}; std::function<void()> task_; std::function<void(const std::exception_ptr&)> error_handler_; void execute() { while(!exit_requested_.load(std::memory_order_acquire)) { try { if (task_) task_(); } catch (...) { auto eptr = std::current_exception(); if (error_handler_) { error_handler_(eptr); } else { // 默认错误处理逻辑 try { std::rethrow_exception(eptr); } catch (const std::exception& e) { std::cerr << "Thread task error: " << e.what() << std::endl; } catch (...) { std::cerr << "Thread task caught unknown non-standard exception" << std::endl; } } } } } };
使用示例
#include <chrono> using namespace std::chrono_literals; class Foo { public: void say_hello(int num) { std::cout << "Hello! count: " << num << std::endl; std::this_thread::sleep_for(2s); } }; int main() { Foo foo; // 用法1:和原方案一致传lambda thread_wrapper th1([&foo](){ foo.say_hello(1); }); // 用法2:直接传成员函数和参数,和std::thread完全一致,不需要手动封装lambda thread_wrapper th2(&Foo::say_hello, &foo, 2); std::this_thread::sleep_for(10s); th1.signal_exit(); th2.signal_exit(); // 不需要手动调用join,析构函数会自动处理 return 0; }
内容的提问来源于stack exchange,提问作者Mdp11
相关产品推荐
相关产品推荐

