简体   繁体   中英

Destructor in a multithreaded environment?

I was wondering what would happen in such a class:

class MyClass
{
private:
    std::vector<int> iVector;
    void Worker()
    {
        //Lots of stuff done with iVector
        //adding, removing elements, etc.
    }
}

Let's say I create a thread (invoked by one of the class member functions) that uses iVector and modifies it. Besides this worker, none of the other member functions of the class reads or modifies this std::vector.

Everything seems fine as worker thread is the only one using iVector.

But what would happen when one instance of the object is destroyed? Even if the object is destroyed after the worker thread is finished, destructor for iVector would be invoked from the main thread. Would this lead to undefined behavior?

Thanks!

Firstly I would suggest running a std::join (or your library equivalent) on the thread in the destructor. This will ensure the thread is properly finished and synchronized before the vector destructor runs. This is important as the vector's lifetime must exceed the thread using it.

The C++11 standard and presumably later ones state in 30.3.1.5:

5: Synchronization: The completion of the thread represented by *this synchronizes with (1.10) the corresponding successful join() return. [ Note: Operations on *this are not synchronized. — end note ]

Now we have to examine 1.10 for more detail, first this section states:

3: The value of an object visible to a thread T at a particular point is the initial value of the object, a value assigned to the object by T, or a value assigned to the object by another thread, according to the rules below.

Honestly, this is difficult to parse, it does not specify exactly what kind of synchronization join offers and seems to imply it synchronizes only the thread itself and not data it has accessed. Therefore I would go the safe route and run atomic_thread_fence(memory_order_acquire) after join in the main thread, and atomic_thread_fence(memory_order_release) in the child thread just before it finishes which should guarantee full happens before semantics and no UB.

If an execution thread is using the ivector class member, and another thread destroys the object with this class member, the continued use of the ivector class member results in undefined behavior.

Even if the object is destroyed after the worker thread is finished, destructor for iVector would be invoked from the main thread. Would this lead to undefined behavior?

No. As you've described, this situation is not undefined behavior. The C++ standard does not require an object to be destroyed by the same execution thread that created the object. It's fine for one execution thread to grow, resize the vector, then go away or stop using the vector, and then a different execution thread destroy the entire object.

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