有没有办法让boost mutex在任何等待的线程上抛出异常?我有一个问题,删除一个对象,但对软件库的性质做了可能线程仍然在对象内的互斥锁等待,并且当互斥锁关闭时抛出一个相当讨厌的异常。我想我可以使用多个互斥计数器,但这可能会导致性能下降。我想要发生的是互斥锁在任何正在等待的线程上抛出异常,以便堆栈展开。是否有一种与平台无关的干净方法?
答案 0 :(得分:3)
这种互斥体在被破坏时抛出的概念似乎是无害的,但是当它实现它的时候,它揭示了你如何思考互斥体的一个缺陷。
让我们来看看一些代码 - 即使它与我将要呈现的代码一样错误,它仍然有助于查看某些代码。
注意:请 不 使用下面的代码,它只能造成无休止的折磨和调试同步问题。< / p>
class throwing_mutex
{
private:
mutex m_;
condition_variable cv_;
bool destroyed_;
bool locked_;
public:
void lock()
{
std::unique_lock<std::mutex> lock(m_);
cv_.wait(lock, [&]() {return !locked_ || destroyed_;}); // Wait until the mutex is unlocked or destroyed.
if (destroyed_) throw runtime_error("The exception was terminated while waiting.");
locked_ = true;
}
void unlock()
{
std::unique_lock<std::mutex> lock(m_);
locked_ = false;
lock.unlock();
cv_.notify_one();
}
~throwing_mutex()
{
std::unique_lock<std::mutex> lock(m_);
destroyed_ = true;
lock.unlock();
cv_.notify_all(); // Let all waiters know we are dead.
}
};
我们现在已经实现了一个互斥体,它完全 你所要求的内容 - 等待throwing_mutex
的所有人都会在throwing_mutex
时抛出异常被毁了。但你能发现这个错误吗?这里有一个巨大的疏忽。
我们已经为等待互斥锁的每个人处理了这个案例,他们会安全地抛出。对于那些已经开始致电lock()
但还没到那里的人来说,我们还没有处理过这种情况。当最终到达他们可以调用lock()
的点时,throw_mutex已经消失了。我们刚刚通过我们有缺陷的方法引入的错误称为use-after-free。如果我们幸运的话,这个错误会很早就清楚地呈现出来,但有时候我们并不那么幸运,我们会被折磨几个小时或几天。我们的throwing_mutex
类无法解决该问题,并且任何需要此类的代码都没有经过深思熟虑的所有权语义。
那么,如果不是通过抛出的互斥量,我们如何解决这个问题呢?我们修复互斥锁的生命周期和由它锁定的对象[s]。
据推测,这是互斥体是一个类的成员。如果是这种情况,则意味着延迟销毁,直到依赖于对象的每个人都完成了它。这是通过使用shared_ptr
来传达的。如果不了解所有权语义的细节,那就是最好的解决方案。希望我已经改变了你对问题的思考方式,足以让你偏离原来的计划,转向更有效的工作。