为什么这个双重互斥锁不会导致死锁?

时间:2016-12-01 20:20:30

标签: c++ multithreading c++11 mutex deadlock

我在我的centos计算机上测试c ++ 11互斥。我尝试双重锁定此互斥锁以使其死锁。但是在我运行之后,一切都很好并且没有发生死锁。

import {PeopleService} from '../providers/people-service/people-service';

export class HomePage {
public people: any;

    constructor(public peopleService: PeopleService){

      }
    }

编译器是g ++ 4.8.5 in centos 3.10.0-327.36.3.el7.x86_64:

#include <thread>
#include <mutex>
#include <iostream>
std::mutex m;
int main()
{
  m.lock();
  m.lock();
  std::cout<<"i am ok"<<std::endl;

  return 0;  
}

3 个答案:

答案 0 :(得分:9)

锁定已被同一个线程锁定的std::mutex未定义的行为,因此它可能会起作用,它可能会失败,它可能会喝掉所有啤酒并呕吐在沙发上。没有保证。

答案 1 :(得分:8)

如果您按原样调用lock两次,则行为未定义 它按预期的方式工作确实是一种有效的未定义行为。

有关详细信息,请参阅here

答案 2 :(得分:2)

对于死锁,您至少需要两个

definition,僵局涉及至少两方。这是由许多作者,以及其他Hoare在他的开创性工作沟通顺序过程中制定的。这也在C ++标准定义中提醒(重点是我的):

  

17.3.8:死锁:一个或多个线程无法继续执行,因为   每个人都被阻止等待一个或多个其他来满足某些人   条件

Anthony Williams在 C ++并发行动

中给出了一个更具说明性的定义
  

两个线程都无法继续,因为每个线程都在等待另一个线程释放它的互斥锁。这种情况称为死锁,它是必须锁定两个或多个互斥锁的最大问题。

因此,根据定义,您不能在单个进程中使用单个线程创建死锁。

不要误解标准

该标准在互斥体上说:

  

30.4.1.2.1 / 4 [注意:如果拥有互斥对象的线程在该对象上调用lock(),程序可能会死锁。]

这是一份非规范性的说明。我认为这与标准的定义相矛盾。从术语的角度来看,锁定自身的进程处于阻塞状态。

但更重要的是,除了死锁术语的问题之外,还有“#34; MAY&#34;允许C ++实现的所述行为(例如,如果它不能在特定OS上检测冗余锁定获取)。但它根本不需要:我相信大多数主流C ++实现都会正常工作,就像你自己经历的一样。

想体验死锁吗?

如果您想体验真正的死锁,或者您只是想知道您的C ++实现是否能够检测到resource_deadlock_would_occur错误,这里只是一个简短的例子。它可以很好但很有可能造成死锁:

std::mutex m1,m2;
void foo() {
    m1.lock();
    std::cout<<"foo locked m1"<<std::endl;
    std::this_thread::sleep_for (std::chrono::seconds(1));
    m2.lock();
    m1.unlock(); 
    std::cout<<"foo locked m2 and releases m1"<<std::endl;
    m2.unlock(); 
    std::cout<<"foo is ok"<<std::endl;
}
void bar() {
    m2.lock();
    std::cout<<"bar locked m2"<<std::endl;
    std::this_thread::sleep_for (std::chrono::seconds(1));
    m1.lock();
    m2.unlock(); 
    std::cout<<"barlocked m1 and releases m2"<<std::endl;
    m1.unlock(); 
    std::cout<<"bar is ok"<<std::endl;
}
int main()
{
    std::thread t1(foo); 
    bar(); 
    t1.join(); 
    std::cout << "Everything went fine"<<std::endl; 
    return 0;  
}

Online demo

通过始终以相同的顺序锁定不同的互斥锁来避免这种死锁。