[英]why is there a crash when class member contains “std::shared_ptr<std::thread>”?
I found that my app will crash when class member contains "std::shared_ptr". 我发现当类成员包含“ std :: shared_ptr”时,我的应用程序将崩溃。 For example:
例如:
#include <thread>
#include <memory>
class Derived {
public:
Derived() {
mThread = std::make_shared<std::thread>(&Derived::callback, this);
}
~Derived() { }
void callback() {}
int add(int x, int y) { return x + y; }
private:
std::shared_ptr<std::thread> mThread;
};
int main() {
Derived * base = new Derived();
delete base;
return 0
}
I would like to know why? 我想知道为什么?
When you are starting threads then you must join or detach them before thread's destructor gets called. 启动线程时,必须先加入或分离它们,然后才能调用线程的析构函数。 I propose to do this in a destructor:
我建议在析构函数中执行此操作:
#include <thread>
#include <memory>
class Derived
{
public:
Derived()
{
mThread = std::make_shared<std::thread>(&Derived::callback, this);
}
~Derived()
{
if(mThread->joinable())
mThread->join();
}
void callback() {}
int add(int x, int y) { return x + y; }
private:
std::shared_ptr<std::thread> mThread;
};
int main()
{
Derived * base = new Derived();
delete base;
return 0;
}
By the way, using shared_ptr in your example is not necessary. 顺便说一下,在您的示例中不必使用shared_ptr 。 You can simply define thread variable:
您可以简单地定义线程变量:
thread mThread;
Start new thread: 启动新线程:
mThread = std::thread(&Derived::callback, this);
And join it, when you need: 并在需要时加入它:
mThread.join();
I think you have a design flaw, as you use shared_ptr for the thread without guaranteeing ownership of Derived. 我认为您有一个设计缺陷,因为您在不保证Derived所有权的情况下对线程使用shared_ptr。
As indicated by snake_style, you should join your thread. 如snake_style所示,您应该加入线程。
I'm gonna argue that you should store the thread by value in your class to guarantee lifetime of Derived: 我要争论的是,您应该按值将线程存储在类中,以保证Derived的生命周期:
#include <thread>
#include <memory>
class Derived {
public:
Derived() {
mThread = std::thread(&Derived::callback, this);
}
~Derived() {
if (mThread.joinable())
mThread.join();
}
void callback() {}
int add(int x, int y) { return x + y; }
private:
std::thread mThread;
};
The if-statement in the Dtor protects you from incorrect behavior when Derived gets moved. 当“派生”被移动时,Dtor中的if语句可保护您免受错误行为的影响。
Another way of guaranteeing ownership is putting Derived in the thread: 保证所有权的另一种方法是将Derived放入线程:
thread = std::thread([d = Derived{}]() mutable { d.callback(); };
This moves the thread variable out of the class. 这会将线程变量移出类。
A third solution could be putting Derived in a shared_ptr and using an alias constructor of shared_ptr to create the threads shared pointer. 第三种解决方案是将Derived放在shared_ptr中,并使用shared_ptr的别名构造函数创建线程共享指针。 I don't work this out as this might be too tricky and you could as well put the shared_ptr as capture in your lambda.
我没有解决这个问题,因为这可能太棘手了,您也可以将shared_ptr作为捕获内容放入lambda中。
If you want to store the thread in a shared_ptr it would be better to create a factory function with a shared_ptr custom deleter which joins the thread. 如果要将线程存储在shared_ptr中,则最好使用带有共享线程的shared_ptr自定义删除器创建工厂函数。
#include <thread>
#include <memory>
#include <iostream>
template<typename... Args>
std::shared_ptr<std::thread> makeThread(Args&&... args)
{
return std::shared_ptr<std::thread>(new std::thread(std::forward<Args>(args)...)
, [](std::thread* t) { t->join(); delete t; });
}
void test(std::int32_t &v)
{
for (int workload = 0; workload < 64; ++workload)
++v;
}
int main(int argc, char *argv[])
{
std::int32_t v = 0;
auto sptr_thread = makeThread(test, std::ref(v));
std::cout << "value before exiting: " << v << std::endl;
return 0;
}
Unlike the std::shared_ptr constructors, std::make_shared does not allow a custom deleter. 与std :: shared_ptr构造函数不同,std :: make_shared不允许自定义删除器。 I would prefer the factory as it's not possible to forget joining the thread
我更喜欢工厂,因为不可能忘记加入线程
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.