繁体   English   中英

当类成员包含“ std :: shared_ptr”时为什么会崩溃 <std::thread> “?

[英]why is there a crash when class member contains “std::shared_ptr<std::thread>”?

我发现当类成员包含“ std :: shared_ptr”时,我的应用程序将崩溃。 例如:

#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
}

我想知道为什么?

启动线程时,必须先加入分离它们,然后才能调用线程的析构函数。 我建议在析构函数中执行此操作:

#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;
}

顺便说一下,在您的示例中不必使用shared_ptr 您可以简单地定义线程变量:

thread mThread;

启动新线程:

mThread = std::thread(&Derived::callback, this);

并在需要时加入它:

mThread.join();

我认为您有一个设计缺陷,因为您在不保证Derived所有权的情况下对线程使用shared_ptr。

如snake_style所示,您应该加入线程。

我要争论的是,您应该按值将线程存储在类中,以保证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;
};

当“派生”被移动时,Dtor中的if语句可保护您免受错误行为的影响。

保证所有权的另一种方法是将Derived放入线程:

 thread = std::thread([d = Derived{}]() mutable { d.callback(); };

这会将线程变量移出类。

第三种解决方案是将Derived放在shared_ptr中,并使用shared_ptr的别名构造函数创建线程共享指针。 我没有解决这个问题,因为这可能太棘手了,您也可以将shared_ptr作为捕获内容放入lambda中。

如果要将线程存储在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;
}

与std :: shared_ptr构造函数不同,std :: make_shared不允许自定义删除器。 我更喜欢工厂,因为不可能忘记加入线程

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM