前几天,我的朋友告诉我他们的项目情况。
有人决定,在并行线程中销毁NotVerySafeClass
的对象(就像异步一样)会很好。它是在不久前实施的。
现在它们崩溃了,因为在主线程中调用了一些方法,而对象被销毁了。
创建了一些解决方法来处理这种情况。
当然,这只是一个不太好的解决方案的例子,但仍然是问题:
是否有某种方法可以在NotVerySafeClass
内部阻止此情况(拒绝运行methods
,如果已调用destructor
,则强制destructor
等待,直到任何正在运行的method
都结束了(让我们假设只有一个method
))?
答案 0 :(得分:7)
不,不,不。这是一个基本的设计问题,它在考虑多线程情况和一般竞争条件时表现出一种常见的误解。
有一件事情可能同样发生,这实际上表明你需要一个所有权概念:函数调用线程可以在对象被销毁后立即调用该函数,因此不再有任何对象并尝试调用它上面的函数是UB,并且由于该对象不再存在,它也没有机会阻止dtor和成员函数之间的任何交互。
答案 1 :(得分:2)
您需要的是健全的所有权政策。为什么代码在仍然需要时会破坏对象?
如果没有关于代码的更多详细信息,std::shared_ptr
可能会解决此问题。根据您的具体情况,您可以使用更轻量级的策略来解决它。
答案 2 :(得分:1)
听起来像一个可怕的设计。你不能使用智能指针来确保只有当没有人拥有任何对它的引用时才会销毁该对象吗?
如果没有,我会使用一些外部同步机制。使用方法同步析构函数真的很尴尬。
答案 3 :(得分:1)
没有可用于防止此情况的方法。
在多线程编程中,如果有其他线程仍在访问它,则需要确保不删除该对象。
如果您正在处理此类代码,需要基本修复
答案 4 :(得分:1)
(不是为了促进糟糕的设计)而是回答你的两个问题:
...如果已经调用了析构函数,则拒绝运行这些方法
您可以使用@snemarch和@Simon(锁定)提出的解决方案来完成此操作。要处理一个线程在析构函数内部,而另一个线程在方法开头等待锁定的情况,您需要在线程之间共享的内存中以线程安全的方式跟踪对象的状态。例如。一个静态原子int,在释放锁之前由析构函数设置为0。一旦获取锁,该方法将检查int,如果为0,则检查b。
...强制析构函数等待,直到任何正在运行的方法结束
@snemarch和@Simon(一个锁)提出的解决方案将处理这个问题。
答案 5 :(得分:0)
没有。只需要设计属性的程序,以便它是线程安全的。
答案 6 :(得分:0)
为什么不使用互斥锁/信号量?在任何方法的开头,互斥锁被锁定,析构函数一直等到互斥锁被解锁。这是一个修复,而不是解决方案。也许你应该改变应用程序的一部分设计。
答案 7 :(得分:0)
简单回答:不。
更长的回答:你可以使用互斥锁来保护你班级中的每个成员函数和析构函数......欢迎遇到僵局机会和性能噩梦。
收集一群暴徒,并将一些设计感传达给那些认为平行破坏是个好主意的“某人”:)