【问题标题】:Holding two mutex locks at the same time同时持有两个互斥锁
【发布时间】:2016-07-20 19:25:09
【问题描述】:

我想知道如果我同时持有两个 boost::scoped_locks 是否会有任何问题。锁正在锁定不同的互斥锁。考虑以下示例:

void foo1()
{
   boost::recursive_mutex::scoped_lock lock(mutex1);
   foo2();
}

void foo2()
{
   boost::recursive_mutex::scoped_lock lock(mutex2);
}

我知道这不会导致死锁。但是有没有其他问题。也许这会导致线程睡眠时间过长?

【问题讨论】:

    标签: c++ thread-safety mutex boost-mutex


    【解决方案1】:

    如果任何人以相反的顺序获得两个互斥锁,这可能会导致死锁。

    void bar1() {
        boost::recursive_mutex::scoped_lock lock(mutex2);
        bar2();
    }
    
    void bar2() {
        boost::recursive_mutex::scoped_lock lock(mutex1);
    }
    

    如下交错的两个线程会死锁:

                                     mutex1  mutex2
    Time    Thread A     Thread B    owner   owner
      0     foo1()                     A
      1                  bar1()        A       B
      2                  bar2()        A       B
      3     foo2()                     A       B
    

    此时线程 A 和 B 处于死锁状态。我不认为boost 提供了对此的保护,尽管底层操作系统可能。

    【讨论】:

    • 感谢您的回答! :)
    【解决方案2】:

    持有多个锁本身不是问题。

    当其他线程尝试以不同的顺序获取相同的锁并且您最终出现ABBA 死锁时,就会出现问题。线程 1 锁定 AB,然后线程 2 想要锁定 B 然后 A 并且最终都被阻塞(如果锁定交错所以 t1 锁定 A,然后 t2 锁定 B 然后两者都阻止试图锁定另一个)等待另一个释放其中一个锁以便能够继续(并释放他们自己持有的锁,这将允许另一个继续)。

    所以,一般的经验法则是;如果您需要获取多个锁,请确保所有线程始终尝试以相同的顺序获取这些锁。

    【讨论】:

    • 感谢您的回答! :)
    • 继续:确保锁定顺序的一种方法是在互斥锁/锁周围使用轻量级包装器,然后让第 i 层的构造函数获取第 (i-1) 层获得的锁的 const ref。那么你不能以任何其他方式构建它。或者 - 使用 C++17 并同时锁定它们。
    • @lorro 我很清楚有 许多 方法可以解决这个问题。但我并没有试图就如何 明智地解决问题的实施提供建议,而只是指出什么 潜在问题是和避免它的一般规则。实施留给读者作为练习。 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-23
    • 2018-05-23
    • 1970-01-01
    • 2012-06-05
    • 2011-10-11
    • 1970-01-01
    相关资源
    最近更新 更多