【问题标题】:How to detect if my program enters a self-deadlock?如何检测我的程序是否进入自死锁?
【发布时间】:2020-07-24 19:47:58
【问题描述】:

我有多线程程序,它只有 1 个互斥锁。我想让程序在它已经拥有锁的情况下尝试获取锁时终止。

我的实际程序相当复杂。当然,我们会尽量避免编程级别的死锁。但万一我们错过了一个边缘情况,我们宁愿它立即失败而不是死锁。

请参阅下面的最小示例。

std::mutex lock;

void f1() {
    std::lock_guard<mutex> guard1(lock);
    // some code ...
}

void f2() {
    std::lock_guard<mutex> guard2(lock);  
    f1(); // Will deadlock here! How can I make it terminate instead of deadlock?
}

【问题讨论】:

  • 在这种情况下你是怎么结束的?重新考虑程序逻辑可能会更好,这样它就不会发生。等一等。这只是一个简化的例子。没关系。忽略那个咆哮的老傻瓜。
  • 学究但......您断言同一线程多次锁定std::mutex "Will deadlock..." 是不正确的。严格来说,这是未定义的行为。
  • @G.M. “严格来说这是未定义的行为” - 除非使用递归互斥锁,否则它是明确定义的。
  • @RemyLebeau 是的,但显示的代码使用了std::mutex lock;

标签: c++ mutex deadlock


【解决方案1】:

std::mutex 没有提供任何机制来完成你所描述的。

您应该注意避免死锁,而不是检测死锁。 Careful programming, including appropriate choice of mutex role and scope, can help.重构也会有所帮助。例如,您可以将示例代码更改为

std::mutex lock;

static void f1_impl() {
    // some code ...
}

void f1() {
    std::lock_guard<mutex> guard1(lock);
    f1_impl();
}

void f2() {
    std::lock_guard<mutex> guard2(lock);  
    f1_impl();
}

但是,如果这不能让您一直到达您想要的位置,那么您可能需要考虑使用std::recursive_mutex 而不是std::mutex。这通过允许已经持有互斥锁的线程再次锁定它来解决问题。

【讨论】:

  • "您可以通过使用 std::mutex::try_lock() 而不是 std::mutex::lock() 来避免死锁 - try_lock() 在被调用时具有未定义的行为已被调用线程锁定的互斥锁,就像 OP 的示例中的情况一样。
  • 删除了有问题的 cmets,@RemyLebeau。无论如何,答案并不需要它们。
  • 我的实际用例是:我们的程序当前使用std::recursive_lock,我们必须非常小心使其可重新输入。我们重构了一些代码,我们认为不再需要std::recursive_lock。我们想用std::mutex 替换它,但如果它自死锁,我们希望它立即失败。
  • 正如我已经说过的,@YixingLiu,std::mutex 不具备这种可能性。但是,您也许可以为完成所需工作的系统互斥原语编写自定义包装器。例如,可以配置 pthread 互斥锁,以便同一线程尝试重新锁定它们会导致错误而不是死锁。您的包装器会检测到这一点并做出适当的响应——例如,通过抛出异常,甚至通过终止程序。但这依赖于关于 C++ 实现的各种假设。
  • 谢谢@JohnBollinger 了解std::mutex 的能力也很有帮助。
猜你喜欢
  • 2010-11-09
  • 1970-01-01
  • 2014-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-12
  • 1970-01-01
相关资源
最近更新 更多