c++ std::thread 在堆栈上

c++ std::thread on stack

我有一个带有普通构造函数的对象。构造函数有很多初始化工作要做。大部分初始化可以异步执行,因此我从构造函数中调用一个新线程。

当线程在堆栈上初始化时,似乎线程在构造函数退出时被销毁,从而导致崩溃。这看起来像这样:

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() 完成后立即清理它?

有没有办法 "automatically" 在线程结束时处理它,使其不被闲置?

本质上,我能否以某种方式获取堆栈上的线程,而不会像我描述的那样崩溃?

您可以从堆栈中调用 std::thread::detach(),但考虑到该对象在 运行 时可能会被长期删除,这 非常 危险。

根据您的要求,最好的选择是确保它在 Init() 和析构函数的末尾加入。 为了简单起见,我认为更好的设计是 join() 在构造函数的末尾。 假设一旦启动线程并且当 Init()被调用,这将是最好的选择。

怎么样:

class MyObject
{
    MyObject ()
    {
        f = std::async (std::launch::async, &MyObject::Init, this);
    }

private:
    void Init ();
    std::future<void> f;
};

这允许您在想要同步任务时执行 f.get ()。如果析构函数是对象的最后一个活动副本,则析构函数将自动加入(如果不希望出现此行为,则可能需要删除复制构造函数)。

请注意,您希望在销毁前的某个时刻进行同步,因为如果 Init 抛出异常,您的析构函数将会。

此外,如果您想走 detach 路线,请参阅 this