在等待线程关闭时提升互斥锁抛出错误

时间:2013-01-13 20:26:13

标签: c++ boost boost-thread

有没有办法让boost mutex在任何等待的线程上抛出异常?我有一个问题,删除一个对象,但对软件库的性质做了可能线程仍然在对象内的互斥锁等待,并且当互斥锁关闭时抛出一个相当讨厌的异常。我想我可以使用多个互斥计数器,但这可能会导致性能下降。我想要发生的是互斥锁在任何正在等待的线程上抛出异常,以便堆栈展开。是否有一种与平台无关的干净方法?

1 个答案:

答案 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来传达的。如果不了解所有权语义的细节,那就是最好的解决方案。希望我已经改变了你对问题的思考方式,足以让你偏离原来的计划,转向更有效的工作。