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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With