繁体   English   中英

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

[英]Is starting an std::thread in a class constructor thread safe?

所以我有一个类似这样的代码(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->Foo_thread = std::thread(&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();
}

我的问题是,我理解得好吗? 我该如何修复此代码? 我想保留构造函数创建线程机制。

谢谢

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

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

暂无
暂无

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

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