将引用传入C++分离线程是否安全?使用shared_ptr是否为更优方案?
问题1解答:引用传入分离线程的安全风险
- 存在非常明确的安全风险,完全有可能出现对象销毁后分离线程仍调用其成员函数的情况,这种行为属于C++标准定义的未定义行为,大概率会触发程序崩溃、脏数据等不可预期的问题。
- 你当前的写法存在明确隐患:你的lambda采用引用捕获
MyObject实例,而定时器内部运行的是分离线程,分离线程的生命周期和创建线程的生命周期完全解绑。哪怕你说MyObject实例在main中仅实例化一次,也无法保证安全:程序退出阶段main函数内的栈对象、全局对象的析构顺序和分离线程的执行时机没有任何同步保障,很有可能MyObject已经被析构,定时器的回调还在执行,直接访问已经释放的内存地址。 - 另外如果后续你调整业务逻辑,
MyObject不再是全程存活的实例,比如变成某业务模块内的局部对象,那这个问题会100%触发。
问题2解答:shared_ptr方案的适用性
shared_ptr是非常合适的替代方案,核心逻辑是通过值捕获shared_ptr延长对象的生命周期,保证只要回调还可能被执行,对象就不会被销毁,修改后的代码参考如下:
// 首先函数参数改为接收shared_ptr<MyObject> std::unique_ptr<Timer> TimerFactory::createTimer(std::chrono::milliseconds period, std::shared_ptr<MyObject> object, void (MyObject::*function)()) { // 值捕获shared_ptr,引用计数会+1,只要callback存在,object就不会被销毁 auto callback = [object, function] { (object.get()->*function)(); }; return std::make_unique<TimerImpl>(period, callback); }
如果你的业务允许MyObject销毁后定时器自动跳过执行,还可以改用weak_ptr做更安全的校验,避免不必要的生命周期延长:
std::unique_ptr<Timer> TimerFactory::createTimer(std::chrono::milliseconds period, std::weak_ptr<MyObject> weakObject, void (MyObject::*function)()) { auto callback = [weakObject, function] { // 先尝试lock提升为shared_ptr,提升成功说明对象还存活 if (auto object = weakObject.lock()) { (object.get()->*function)(); } }; return std::make_unique<TimerImpl>(period, callback); }
额外补充
如果你坚持要使用引用传递,必须引入同步机制保证对象生命周期大于定时器的所有回调执行时机:比如在main退出前先主动停止定时器,等待定时器线程完全退出后再析构MyObject实例。但这种手动管理的方式对后续业务改动的兼容性极差,非常容易漏处理触发bug,远不如智能指针自动管理的方案稳妥。
内容的提问来源于stack exchange,提问作者sangelsen
相关产品推荐
相关产品推荐

