我有一个普通构造函数的对象。构造函数有很多初始化要做。大部分初始化都可以异步执行,所以我从构造函数中调用一个新线程。
当线程在堆栈上初始化时,看起来线程在构造函数退出时被破坏而导致崩溃。这看起来像这样:
class MyObject
{
MyObject()
{
// Typical initialization
// ...
// Time consuming initialization
std::thread(&MyObject::Init; this); // Create new thread to call Init();
// Crash when exit MyObject() here
}
void Init()
{
// Time consuming operations
}
};
替代方法(可行)是在堆上创建线程。
class MyObject
{
std::thread* StartupThread;
MyObject()
{
// Typical initialization
// ...
// Time consuming initialization
StartupThread = new std::thread(&MyObject::Init; this); // Create new thread to call Init();
// Crash when exit MyObject() here
}
~MyObject()
{
StartupThread->join();
delete StartupThread;
}
void Init()
{
// Time consuming operations
}
};
我的问题
是否有任何伤害是离开未加入的&未使用的线程对象在对象的生命周期内是活着的,还是应该在Init()
完成后立即尝试清理它?
有没有办法在线程完成时“自动”处理线程,这样它就不会留下来?
基本上,我可以以某种方式获取堆栈中的线程而不会像我描述的那样崩溃吗?
答案 0 :(得分:3)
怎么样:
class MyObject
{
MyObject ()
{
f = std::async (std::launch::async, &MyObject::Init, this);
}
private:
void Init ();
std::future<void> f;
};
这使您可以在要同步任务时执行f.get ()
。如果析构函数是对象的最后一个活动副本,则它将自动连接(如果您不希望出现此行为,则可能需要删除复制构造函数。)
请注意,您希望在销毁之前的某个时刻进行同步,因为如果Init
抛出异常,您的析构函数将会。
另外,如果您想要detach
路线,请参阅this。
答案 1 :(得分:0)
您可以从堆栈中调用std::thread::detach()
,但这是非常危险,因为该对象可能会在其仍在运行时被删除。
根据您的要求,最好的选择是确保它在Init()
和解构函数的末尾加入。 我认为更好的设计是为了简单起见,在构造函数的末尾为假设一旦启动线程并且{{1}时没有其他处理要做调用,这将是最好的选择。join()
。