簡體   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