我想知道在这样一个班级会发生什么:
class MyClass
{
private:
std::vector<int> iVector;
void Worker()
{
//Lots of stuff done with iVector
//adding, removing elements, etc.
}
}
假设我创建了一个使用iVector并修改它的线程(由其中一个类成员函数调用)。除了这个worker之外,该类的其他成员函数都没有读取或修改这个std :: vector。
一切似乎都很好,因为工作线程是唯一使用iVector的人。
但是当一个对象实例被销毁时会发生什么?即使在工作线程完成后对象被销毁,也会从主线程调用iVector的析构函数。这会导致不确定的行为吗?
谢谢!
答案 0 :(得分:3)
首先,我建议在析构函数的线程上运行std::join
(或等效的库)。这将确保在向量析构函数运行之前正确完成并同步线程。这很重要,因为向量的生命周期必须超过使用它的线程。
C ++ 11标准,可能是后来的30.3.1.5中的状态:
5:同步:完成由* this表示的线程 与(1.10)同步成功的join()返回。 [ 注意:* this上的操作不同步。 - 结束说明]
现在我们必须检查1.10以获取更多细节,首先是本节说明:
3:特定点处线程T可见的对象的值 是对象的初始值,是由对象分配的值 T,或由另一个线程分配给该对象的值,根据 以下规则。
老实说,这很难解析,它没有详细说明连接提供什么样的同步,似乎暗示它只同步线程本身而不是它已访问的数据。因此,我会在加入主线程后运行atomic_thread_fence(memory_order_acquire)
并在子线程完成之前运行atomic_thread_fence(memory_order_release)
,这应该保证在语义之前完全发生并且没有UB。
答案 1 :(得分:2)
如果执行线程正在使用ivector
类成员,而另一个线程使用此类成员销毁该对象,则继续使用ivector
类成员会导致未定义的行为。
即使在工作线程完成后对象被销毁, 将从主线程调用iVector的析构函数。将 这导致了未定义的行为?
没有。正如您所描述的,这种情况并非未定义的行为。 C ++标准不要求对象被创建对象的同一执行线程销毁。一个执行线程增长,调整向量大小,然后消失或停止使用向量,然后一个不同的执行线程破坏整个对象,这很好。