简体   繁体   English

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

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

So I have a code something like this (C++11):所以我有一个类似这样的代码(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();
}

If I understand well, the f pointer and the Foo instance lives in the main thread.如果我理解得很好,f 指针和 Foo 实例存在于主线程中。 In the constructor, this->Foo_thread = std::thread(&Foo:SartLoop, this);在构造函数中, this->Foo_thread = std::thread(&Foo:SartLoop, this); , the address of the Foo instance is passed to the std::thread, so this thread can access this object's members, for example in Foo::StartLoop(): this->vec.push_back. ,Foo 实例的地址被传递给 std::thread,因此该线程可以访问该对象的成员,例如在 Foo::StartLoop(): this->vec.push_back 中。

However, the Foo class have a public AddToVec(), so in the main() I could write:然而,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();
}

My question is, do I understand well?我的问题是,我理解得好吗? How can I fix this code?我该如何修复此代码? I'd like to keep the constructor-creates-thread mechanism.我想保留构造函数创建线程机制。

Thank you谢谢

It causes data race to call f->AddToVec(78);它导致数据竞争调用 f->AddToVec(78); f->setter(67); f->setter(67); in main.在主要。 Without them, accessing the object under construction with this pointer is safe, in the sense that it's not UB and the language standard doesn't prohibit that.没有它们,使用this指针访问正在构造的对象是安全的,因为它不是 UB 并且语言标准不禁止这样做。 But in practice, use of this under construction is not recommended and experienced developers often try to avoid because it leads to problems as code evolves:但在实践中,不推荐在构造中使用this ,并且有经验的开发人员通常会尽量避免,因为随着代码的发展,它会导致问题:

  • if the class happens to be polymorphic, calling virtual function before constructor finishes causes UB when a part of base classes are not fully initialized如果类恰好是多态的,则在构造函数完成之前调用虚函数会在基类的一部分未完全初始化时导致 UB
  • before the completion of constructor, the class invariants are not satisfied在构造函数完成之前,类不变量不满足

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

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