在类构造函数线程中启动 std::thread 是不是安全?

Posted

技术标签:

【中文标题】在类构造函数线程中启动 std::thread 是不是安全?【英文标题】:Is starting an std::thread in a class constructor thread safe?在类构造函数线程中启动 std::thread 是否安全? 【发布时间】:2019-12-01 20:53:31 【问题描述】:

所以我有一个类似这样的代码(C++11):

class Foo

    private:
        std::vector<int> vec;
        int val;
        std::thread Foo_thread;
    public:
        Foo();
        void StartLoop();
        void WaitTermination()  this->Foo_thread.join(); 
        void AddToVec(int dummy)  vec.push_back(dummy); 
        void setter(int val)  this->val = val; 
;

void Foo::StartLoop()

    while (true)
    
        // some code . . .
        this->vec.push_back(something);
    


Foo::Foo()

    this->Foo_thread = std::thread(&Foo:SartLoop, this);


int main()

    Foo* f = new Foo;
    f->WaitTermination();

如果我理解得很好,f 指针和 Foo 实例位于主线程中。在构造函数this-&gt;Foo_thread = std::thread(&amp;Foo:SartLoop, this);中,Foo实例的地址被传递给std::thread,所以这个线程可以访问这个对象的成员,例如在Foo::StartLoop()中:this->vec.push_back。

但是,Foo 类有一个公共的 AddToVec(),所以我可以在 main() 中写:

int main()

    Foo* f = new Foo;
    f->AddToVec(78); // at this point, we modify the private vec member, both from the main thread and in the std::thread, if I undersand well
    f->setter(67); // same problem, however it's easier to declare val as std::atomic<int>, but the above one is really problematic
    f->WaitTermination();

我的问题是,我理解得好吗?如何修复此代码?我想保留constructor-creates-thread机制。

谢谢

【问题讨论】:

本质上,如果多个线程修改数据,则需要使用同步原语,如std::mutex 在 main() 中,如果我不做 f->AddToVec(78); f->setter(67);来电,我的代码没问题? 好吧,你拼错了“SartLoop”,一方面:( 多线程很难。您需要阅读C++ Concurrency in Action 之类的书籍或学习一些课程,以至少了解基本原理。否则,您将获得损坏的数据或死锁。 【参考方案1】:

导致数据竞争调用 f->AddToVec(78); f->setter(67);主要。没有它们,使用 this 指针访问正在构建的对象是安全的,因为它不是 UB 并且语言标准并不禁止这样做。 但在实践中,不建议使用正在构建的this,有经验的开发人员经常会尽量避免,因为它会随着代码的发展而导致问题:

如果类碰巧是多态的,调用虚函数 当部分基类未完全初始化时,在构造函数完成之前导致 UB 构造函数完成前,类不变量不满足

【讨论】:

以上是关于在类构造函数线程中启动 std::thread 是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章

使用成员函数启动线程

使用成员函数启动线程

使用类构造函数在线程中启动成员函数

c++11的std::thread能用类的成员函数构造一个线程吗?语法怎样?

C++ 多线程std::thread 详解

C++ 多线程std::thread 详解