C++ 为什么这个双互斥锁不会导致死锁?
我在centos计算机上测试c++11互斥。我尝试双重锁定这个互斥锁以产生死锁。但在我运行它之后,一切都很好,没有死锁发生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; }
#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;
}