我们提供安全,免费的手游软件下载!
今天我在复习项目过程中积累的技术案例时,回顾了一个小的coredump案例。当时,即使是小组里的一些资深同事也没有发现问题所在。然后我在周末花了两三个小时查找并解决了这个问题。今天,我要做一次系统总结,给出一个能够复现该问题的案例代码。这个案例代码相对简单,便于学习和理解。
/**
* @brief 关键字:lambda、多线程、std::shared_ptr 隐式向上转换
* g++ main.cc -std=c++17 -O3 -lpthread
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
// 定义简易线程池...
上述的例子代码,会出现coredump,或者是没有执行派生类的DoSomething。不符合预期的原因在于,这份代码往一个线程里post lambda函数,lambda函数引用捕获智能指针对象,这是一个临时对象,其离开使用域之后会被析构掉,导致lambda函数在异步线程执行时访问到一个"野引用"出错。而之所以捕获的智能指针是临时对象,是因为调用User.DoJobAsync时发生了类型的向上转换。
上述的例子还比较容易看出来问题点,但当我们的项目代码层次较深时,这类错误就非常难发现。因此之前团队里的资深同事也都无法察觉问题所在。
这类问题有多种解决办法:
(1)方法1:避免出现隐式转换,消除临时对象;
(2)方法2:函数和lambda捕获都修改为裸指针,消除临时对象;引用本质上是指针,需要关注生命周期。既然采用引用参数就表示调用者需要保障对象的生命周期,智能指针的引用在用法上跟指针无异,那么这里不如用裸指针,让调用者更清楚自己需要保障对象的生命周期;
(3)方法3:异步执行时采用值捕获/值传递,不采用引用捕获。值捕获可能导致性能浪费,但具体到本文的例子,这里的性能开销是一个智能指针对象的构造,性能损耗不大,是可接受的。
热门资讯