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

C++ 为什么这个双互斥锁不会导致死锁?,c++,multithreading,c++11,mutex,deadlock,C++,Multithreading,C++11,Mutex,Deadlock,我在centos计算机上测试c++11互斥。我尝试双重锁定这个互斥锁以产生死锁。但在我运行它之后,一切都很好,没有死锁发生 #include <thread> #include <mutex> #include <iostream> std::mutex m; int main() { m.lock(); m.lock(); std::cout<<"i am ok"<<std::endl; return 0; }

我在centos计算机上测试c++11互斥。我尝试双重锁定这个互斥锁以产生死锁。但在我运行它之后,一切都很好,没有死锁发生

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

  return 0;  
}

锁定一个已经被同一线程锁定的std::mutex是未定义的行为,因此它可能会工作,可能会失败,可能会喝掉你所有的啤酒,然后在沙发上呕吐。不保证。

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

有关更多详细信息,请参阅。

有关死锁,您至少需要两个 到目前为止,僵局至少涉及两方。这是许多作者在他的开创性著作《沟通顺序过程》中提出的。这也提醒了C++标准定义中强调的是我:

17.3.8:死锁:一个或多个线程无法继续执行,因为 每一个都被阻塞,等待一个或多个其他的满足某些要求 状况

Anthony Williams在C++ 动作并发< /P>中给出了一个更为说明性的定义 两个线程都不能继续,因为每个线程都在等待另一个线程释放它的互斥锁。这种情况称为死锁,这是必须锁定两个或多个互斥锁的最大问题

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

不要误解标准 标准在互斥体上说:

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

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

但是更重要的是,除了死锁术语之外,Word可以允许C++实现的行为,例如如果它不能在特定OS上检测冗余锁获取。但这根本不需要:我相信大多数主流C++实现都会很好,正如你自己经历过的一样。 想体验一下死锁吗? <>如果您想体验真正的死锁,或者如果您想简单地了解C++实现是否能够检测到RealCydiDeLoCuthOrthyError发生错误,这里有一个简短的例子。它可能进展顺利,但很有可能造成死锁:

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;  
}

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

这并不能回答问题。@PeteBecker问题是关于死锁的。因此,这很好地回答了这个问题:OP的代码片段不会创建死锁,并解释了什么是死锁。OP问为什么他的代码不等待For,那么我同意你的观点。看起来C++标准在它说的时候出错了。(注:如果一个互斥对象拥有一个线程,它会死锁,这个锁调用那个对象……线程。互斥。类)/4.或者,天哪,死锁可能比维基百科上的死锁有更广泛的含义。不管怎样,问题显然是为什么问题中的代码没有锁定,而不是其他代码是否会陷入死锁。@PeteBecker我认为死锁这个术语比C++11标准早得多,我很确定当C他在1985年的《通信顺序进程》一书中写道,他在并发编程方面的开创性工作,任何没有周期的不间断进程网络都不会死锁,他真的没有考虑单个进程线程能够死锁。事实上,他把这个单线程阻塞称为停止-请注意,我不是在喊,但是HOLE使用了一个系统的大写来表示这个状态。@ PeteBecker我编辑了我的答案来澄清我的观点,这次是用C++标准自己定义的。你能在标准中给出一个引用吗?我找不到在互斥部分30.4.1.2.1中未定义的行为的证据。@克里斯多夫:请给出完整的引用而不是仅仅SE。Action编号。该标准有许多版本。@Christophe:n3690§30.4.1.2^7要求:如果m的类型为std::mutex…,则调用线程不拥有该互斥体。
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;  
}