C++ 多态对象销毁与并发

C++ 多态对象销毁与并发,c++,multithreading,c++11,parallel-processing,delete-operator,C++,Multithreading,C++11,Parallel Processing,Delete Operator,我有一个多态对象o和两个线程T1和T2 o的最派生类的析构函数在返回之前等待T2的终止 当T2调用o的一些虚拟函数时,让T1删除o安全吗?(我的意思是不使用互斥或任何其他类型的同步机制) 我相信它应该是安全的,除非在调用的第一个析构函数完成之前允许delete修改o(比如它指向vtable的指针)。是这样吗?想象一下,您的类有一些动态分配的成员, T1的析构函数可以在T2仍在访问这些成员时解除分配这些成员。 这将导致未定义的行为 只要您能确保T1的析构函数和T2的函数不在同一个成员上运行,您就

我有一个多态对象
o
和两个线程
T1
T2

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

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



我相信它应该是安全的,除非在调用的第一个析构函数完成之前允许
delete
修改
o
(比如它指向vtable的指针)。是这样吗?

想象一下,您的类有一些动态分配的成员,
T1
的析构函数可以在
T2
仍在访问这些成员时解除分配这些成员。
这将导致未定义的行为

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


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

首先,如果可以避免这种情况,那么它很脆弱且容易出错。您可以让它工作,但代码中的微小更改可能会破坏它

如果complete object析构函数中的块所做的唯一事情是等待另一个线程的完成,并且假设基本对象具有虚拟析构函数或者直接销毁了complete object,那么这样做是安全的。在析构函数体完成之前,对象的任何成员都不会被销毁,基也不会被销毁。这意味着其他线程正在使用的任何子对象都不会在其完成之前被销毁(并让第一个线程完成析构函数的主体)


也就是说,再次尝试重新设计代码。

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

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

  • T2
    可以访问
    o的基类方法
  • 在线程
    T1
    中,输入
    o
    的dtor
  • 线程
    T2
    退出
  • 在线程
    T1
    中,
    o
    的数据或返回
  • 无法再调用
    o
    的基类方法

  • 我不会这么做。对我来说,这听起来像是在没有网的高压线上跑步。对我来说,这似乎是一个间歇性崩溃的机会。“在析构函数主体完成之前,对象的所有成员都不会被销毁,基本成员也不会被销毁”,如果有一个动态分配的成员(例如
    char*
    )通过调用
    delete
    解除分配,会发生什么情况?在析构函数体完成之前,该成员确实已被删除。如果另一个线程正在访问此特定成员,则存在问题。@Als:如果仔细阅读答案,您会注意到它首先定义一组前提,以确定析构函数体做什么或不做什么。所述的前提比它们需要的更严格,但无论如何,如果块[…]所做的唯一事情是等待,则对任何指针成员调用
    delete
    。。。此外,在以后的维护过程中,有人可能会向析构函数添加破坏它的代码,这一事实属于代码中的小更改的描述范围,可能会破坏它。脆弱和错误提示我添加了注释,因为除非仔细阅读答案,否则细节不容易显现。