首页 > 解决方案 > 此代码段中是否会发生死锁,为什么?

问题描述

以下代码片段中是否可能出现死锁:

void f()
{
    {
        std::lock_guard <std::mutex> inner (lock1);
        // do something and conditionally return
    }
    std::lock_guard <std::mutex> outer (lock2);
    // do something
}

IOW,如果多个线程调用这个函数,会发生死锁吗?

我不太确定,所以任何帮助将不胜感激。

标签: c++c++11

解决方案


如果你重构你的代码,使每个范围都是一个函数,那么很明显锁永远不会被单个线程同时锁定:

std::mutex lock1;
std::mutex lock2;

// One mutex in g => No deadlock possible
void g()
{
    std::lock_guard <std::mutex> inner (lock1);
    // do something
}

// One mutex in h => No deadlock possible
void h()
{
    std::lock_guard <std::mutex> outer (lock2);
    // do something 
} 

// No mutex in f => No deadlock possible
void f()
{
    g();
    h();
}

由此您可以得出结论,当线程正在请求锁时,它不会持有锁。这使得死锁是不可能的。您可以通过创建一个简单地包装并添加跟踪的BasicLockable对象来自行检查:std::mutex

class PrinterMutex {
  public:
  PrinterMutex(const std::string& _name) : name(_name) {}
  ~PrinterMutex() {}
  void lock() {
    std::cout << "lock : " << name << std::endl;
    m.lock();
  }
  void unlock() {
    std::cout << "unlock : " << name << std::endl;
    m.unlock();
  }
  private:
    std::mutex m;
    std::string name;
};

PrinterMutex lock1("lock1");
PrinterMutex lock2("lock2");

int main()
{
    {
        std::lock_guard <PrinterMutex> inner (lock1);
        // do something and conditionally return
    }
    std::lock_guard <PrinterMutex> outer (lock2);
    // do something
} 

跟踪会告诉你,一个线程总是在请求一个锁之前释放一个锁,这使得死锁是不可能的。

如果您的代码中确实需要多个互斥锁,则应使用std::lock多个 Lockable 对象来通过死锁避免算法锁定互斥锁。

std::mutex lock1;
std::mutex lock2;
void g()
{
        std::lock(lock1, lock2);
        std::lock_guard<std::mutex> inner (lock1, std::adopt_lock);
        std::lock_guard<std::mutex> outer (lock2, std::adopt_lock);
        // Do something
}

推荐阅读