根据C++规范,std::recursive_mutex支持在同一thread内递归加锁,而std::mutex不支持。
下面这代码,在VS2017中运行出错,emmm……。
#include<iostream>
#include<mutex>
std::mutex m;
int main(int argc, char ** argv)
{
std::lock_guard<std::mutex> ll(m);
std::cout << "111111111111" << std::endl;
std::lock_guard<std::mutex> ll2(m);
std::cout << "222222222222" << std::endl;
std::cout << "Hello world" << std::endl;
return 0;
}
但是在Linux中(ubuntu16.04 + g++5.4),却能成功执行。
很明显,这不符合C++的规范啊。
调试发现,在下面这个函数里,__gthread_active_p返回了0,所以__gthread_mutex_lock也返回了0。注意,748行不会走,也就是说不会调用pthread_mutex_lock。
于是std::mutex::lock()成功返回了。
所以,程序运行没有阻塞。
下面,在代码里,创建一个子线程:
#include<iostream>
#include<mutex>
#include<thread>
std::mutex m;
void sub_thread(void)
{
while (1)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main(int argc, char ** argv)
{
std::thread(sub_thread).detach();
std::lock_guard<std::mutex> ll(m);
std::cout<< "111111111111" << std::endl;
std::lock_guard<std::mutex> ll2(m);
std::cout<< "222222222222" << std::endl;
std::cout<< "Hello world" << std::endl;
return 0;
}
再编译运行,神奇的事情发生了,阻塞住了。
综上说明,std::mutex确实是不支持在同一个thread里递归加锁的。但是在Linux里,程序运行时判断了一个条件,然后令std::mutex::lock()直接成功返回了,根本没有调用pthread_mutex_lock。
那么__gthread_active_p()是动态判断还是静态判断?是判断进程中有没有多个线程吗?即,这个函数是不是判断出,当前进程里只有一个主线程在运行,就会返回0?
回到最开始的代码,编译这段代码,但是强制链接pthread库。神奇的事情又发生了:
综上猜测,如果程序运行时没有加载pthread库,__gthread_active_p()就会返回0,不会调用pthread_mutex_lock。否则,就要老老实实地调用pthread_mutex_lock,即使现在只有一个主线程在运行。
第二次加锁会阻塞,是符合预期的。但是VS2017里居然报错……Windows嘛,你们开心就好。