销毁对象时运行方法
前几天,我的朋友告诉我他们项目中的情况。 有人决定,最好在并行线程中(例如异步)销毁 NotVerySafeClass
的对象。它是前一段时间实施的。 现在他们崩溃了,因为在主线程中调用了一些方法,而对象被销毁了。 创建了一些解决方法来处理这种情况。
当然,这只是一个不太好的解决方案的例子,但仍然是一个问题:
是否有某种方法可以在 NotVerySafeClass
内部防止这种情况(拒绝运行 methods
,如果析构函数已被调用,并强制析构函数等待,直到任何正在运行的方法结束(假设只有一个方法))?
A few days ago my friend told me about the situation, they had in their project.
Someone decided, that it would be good to destroy the object of NotVerySafeClass
in parallel thread (like asynchronously). It was implemented some time ago.
Now they get crashes, because some method is called in main thread, while object is destroyed.
Some workaround was created to handle the situation.
Ofcourse, this is just an example of not very good solution, but still the question:
Is there some way to prevent the situation internally in NotVerySafeClass
(deny running the methods
, if destructor
was called already, and force the destructor
to wait, until any running method
is over (let's assume there is only one method
))?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
不,不,不。这是一个基本的设计问题,它显示了在考虑多线程情况和一般竞争条件时的常见误解。
有一件事情同样可能发生,这确实表明您需要一个所有权概念:函数调用线程可以在对象被销毁后立即调用该函数,因此不再有对象并尝试调用它上面的函数是 UB,并且由于该对象不再存在,它也没有机会阻止 dtor 和成员函数之间的任何交互。
No, no and no. This is a fundamental design issue, and it shows a common misconception in thinking about multithreaded situations and race conditions in general.
There is one thing that can happen equally likely, and this is really showing that you need an ownership concept: The function calling thread could call the function just right after the object has been destroyed, so there is no object anymore and try to call a function on it is UB, and since the object does not exist anymore, it also has no chance to prevent any interaction between the dtor and a member function.
您需要的是健全的所有权政策。为什么代码在仍然需要对象时却销毁了该对象?
如果没有有关代码的更多详细信息,
std::shared_ptr
可能会解决此问题。根据您的具体情况,您也许可以通过更轻量级的策略来解决。What you need is a sound ownership policy. Why is the code destroying the object when it is still needed?
Without more details about the code, a
std::shared_ptr
would probably solve this issue. Depending on your specific situation, you may be able to solve it with a more lightweight policy.听起来是一个可怕的设计。难道不能使用智能指针来确保只有当没有人持有任何引用时对象才会被销毁吗?
如果没有,我会使用一些外部同步机制。将析构函数与方法同步确实很尴尬。
Sounds like a horrible design. Can't you use smart pointer to make sure the object is destroyed only when no-one holds any references to it?
If not, I'd use some external synchronization mechanism. Synchronizing the destructor with a method is really awkward.
没有任何方法可以用来防止这种情况。
在多线程编程中,您需要确保如果有其他线程仍在访问某个对象,则该对象不会被删除。
如果您正在处理此类代码,它需要根本修复
There is no methods that can be used to prevent this scenario.
In multithread programming, you need to make sure that an object will not be deleted if there are some others thread still accessing it.
If you are dealing with such code, it needs fundamental fix
(不是为了宣扬糟糕的设计)而是为了回答您的两个问题:
您可以使用@snemarch和@Simon(锁)提出的解决方案来执行此操作。要处理一个线程位于析构函数内,而另一个线程在方法开头等待锁的情况,您需要在线程之间共享的内存中以线程安全的方式跟踪对象的状态。例如,在释放锁之前,析构函数将静态原子 int 设置为 0。该方法在获取锁后检查 int 是否存在,如果为 0,则释放。
@snemarch和@Simon(锁)提出的解决方案将处理这个问题。
(Not to promote bad design) but to answer your two questions:
You can do this with the solution proposed by @snemarch and @Simon (a lock). To handle the situation where one thread is inside the destructor, while another one is waiting for the lock at the beginning of your method, you need to keep track of the state of the object in a thread-safe way in memory shared between threads. E.g. a static atomic int that is set to 0 by the destructor before releasing the lock. The method checks for the int once it acquires the lock and bails if its 0.
The solution proposed by @snemarch and @Simon (a lock) will handle this.
不需要。只需要正确设计程序,使其成为线程安全的。
No. Just need to design the program propertly so that it is thread safe.
为什么不使用互斥体/信号量?在任何方法开始时,互斥锁都会被锁定,析构函数会等待直到互斥锁被解锁。这是修复,而不是解决方案。也许您应该更改应用程序的一部分的设计。
Why not make use of a mutex / semaphore ? At the beginning of any method the mutex is locked, and the destructor wait until the mutex is unlocked. It's a fix, not a solution. Maybe you should change the design of a part of your application.
简单的回答:不。
答案有点长:您可以使用互斥锁来保护类中的每个成员函数和析构函数...欢迎来到死锁机会和性能噩梦。
聚集一群暴徒,向认为并行破坏是个好主意的“某人”敲打一些设计意识:)
Simple answer: no.
Somewhat longer answer: you could guard each and every member function and the destructor in your class with a mutex... welcome to deadlock opportunities and performance nightmares.
Gather a mob and beat some design sense into the 'someone' who thought parallel destruction was a good idea :)