Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does joining a member thread accessing other members of its parent class in the parent's destructor result in undefined behavior?

One of my coworkers claims that as soon as an object's destructor invocation begins, all accesses to the object's members done by a thread (that's a member of the object itself) are UB.

This implies that calling std::thread::join during the destructor of an object is UB if the thread is accessing any of the object's other members.

I briefly looked in the latest standard draft, under "Object Lifetime", but couldn't find something that gave me a conclusive answer.

Does the following code (on wandbox) introduce undefined behavior? What's the part of the standard that clarifies this interaction?

struct A 
{
    atomic<bool> x{true};
    thread t;

// Capturing 'this' is part of the issue.
// The idea is that accessing 'this->x' becomes invalid as soon as '~A()' is entered.
//           vvvv
    A() : t([this]
            { 
                while(x) 
                {
                    this_thread::sleep_for(chrono::milliseconds(100)); 
                }
            }) 
    { 
    }

    ~A() 
    { 
        x = false; 
        t.join(); 
    }
};

int main()
{
    A a;
}
like image 562
Vittorio Romeo Avatar asked Jan 06 '23 03:01

Vittorio Romeo


1 Answers

This is not undefined behavior. If we look at [class.dtor]/8 we have

After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class X calls the destructors for X’s direct non-variant non-static data members, the destructors for X’s direct base classes and, if X is the type of the most derived class (12.6.2), its destructor calls the destructors for X’s virtual base classes.

which states the the non-static members of the class are destroyed after the body of the destructor is ran. That means all the members are alive in the destructor and manipulating x and calling join behave just like they would in a normal member function. The only difference is after the body of the destructor is ran then the members themselves will be destroyed.

like image 90
NathanOliver Avatar answered Jan 07 '23 16:01

NathanOliver