简体   繁体   中英

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

So I have a code something like this (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. In the constructor, 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.

However, the Foo class have a public AddToVec(), so in the main() I could write:

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->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. 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:

  • 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
  • before the completion of constructor, the class invariants are not satisfied

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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