【问题标题】:What is the lifetime of C++ member variables when running in a std::thread?在 std::thread 中运行时,C++ 成员变量的生命周期是多少?
【发布时间】:2019-12-28 07:31:50
【问题描述】:
#include <iostream>
#include <string>
#include <thread>

using namespace std;

struct safe_thread : public thread
{
    using thread::thread;

    safe_thread& operator=(safe_thread&&) = default;

    ~safe_thread()
    {
        if (joinable())
        {
            join();
        }
    }
};

struct s
{
    safe_thread t;
    std::string text = "for whatever reason, this text will get corrupted";

    s() noexcept
    {
        std::cout << text << '\n'; // it works in constructor as expected
        t = safe_thread{ [this]
                         { long_task(); }};
    }

    void long_task()
    {
        for (int i = 0; i < 500; ++i)
        {
            std::cout << text << '\n'; // the text gets corrupted in here
        }
    }
};

int main()
{
    s s;
}

在上面的代码中,text 变量将在构造函数中正确打印。但是,在单独线程中运行的 long_task() 函数中,文本被破坏(它在另一台机器上彻底崩溃)。怎么会这样?如果safe_thread 的析构函数将在struct s 的析构函数中运行,那么threadtext 的生命周期不应该同样长吗?即当 s 超出main() 的范围时,它们都会超出范围?

【问题讨论】:

  • 你真的要制作s()noexcept吗?如果线程无法启动,std::thread 构造函数可以抛出,如果分配失败,std::thread 可以抛出 std::bad_alloc

标签: c++ c++11 lifetime stdthread


【解决方案1】:

您的问题在于s 类中的声明成员变量的顺序。

int main()
{
    s s;
    // here is called dtor of S
}

当调用析构函数时,数据成员按照其声明的相反顺序被销毁。你有:

safe_thread t; // [2]
std::string text = "for whatever reason, this text will get corrupted"; // [1]

所以当第一个字符串 [1] 被销毁时,然后 [2] 线程的析构函数被调用,并且在此调用期间您的程序加入。但随后它正在访问被破坏的text 变量。是UB。

将顺序改为:

std::string text = "for whatever reason, this text will get corrupted";
safe_thread t;

通过这种方法,在加入t 时,text 变量仍然可见且不会被删除。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-20
    • 2010-09-19
    相关资源
    最近更新 更多