多态对象破坏和并发

时间:2012-09-17 03:15:53

标签: c++ multithreading c++11 parallel-processing delete-operator

我有一个多态对象o和两个帖子T1T2

o派生类的析构函数在返回之前等待T2的终止。

T1调用o的某些虚拟函数时,让T2删除o是否安全? (我的意思是不使用互斥或​​任何其他类型的同步机制)


我相信它应该是安全的,除非delete被允许修改o(就像它指向vtable的指针),甚至在第一个析构函数被调用完成之前。是这种情况吗?

3 个答案:

答案 0 :(得分:2)

首先,如果你可以避免这种情况,那就很脆弱且容易出错。你可以使它工作,但代码中的细微变化可能会破坏它。

如果完整对象析构函数中的块唯一做的是等待另一个线程的完成,并假设基础对象具有虚拟析构函数或者直接销毁整个对象,则然后这是安全这样做。在析构函数的主体完成之前,对象的所有成员都不会被销毁,也不是基础。这意味着另一个线程正在使用的子对象都不会在它完成之前被销毁(并让第一个线程完成析构函数的主体)。

话虽如此,再次尝试重新设计代码。

答案 1 :(得分:0)

想象一下你的班级有一些动态分配成员的场景,
T1的析构函数可能会在T2仍然访问这些成员时解除分配这些成员。
这将导致未定义的行为。

只要你能确保T1的析构函数和T2的函数不在同一个成员上运行就是安全的,但是如果你不能确保它,那么你肯定需要一些同步。

请注意,基本逻辑保持不变,没有两个线程可以在同一实体上同时读写,否则最终会出现竞争条件和同步问题。

答案 2 :(得分:0)

如上所述,这是有风险的,但您可以采取一些措施来降低风险。线程同步的责任应该是派生程度最高的类的唯一责任。特别是,除了析构函数之外,这个派生类最多的类不应该有任何虚函数。

这种设计意味着T2不能在最派生的类中调用任何函数。它最多可以依赖于o基类的成员,并且这些成员将在最大派生的dtor返回之前有效 - 这将在T2退出之后。这意味着以下序列不会被重新排序,除了可能的步骤2和3(无害)

  1. T2可以访问o
  2. 的基类方法
  3. 在帖子T1中,输入了o的dtor
  4. 线程T2退出。
  5. 在帖子T1中,o的dtor返回
  6. 无法再调用o的基类方法。