Linux中std::mutex可递归加锁问题研究

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

无标题.png

但是在Linux中(ubuntu16.04 + g++5.4),却能成功执行。
image.png

很明显,这不符合C++的规范啊。
调试发现,在下面这个函数里,__gthread_active_p返回了0,所以__gthread_mutex_lock也返回了0。注意,748行不会走,也就是说不会调用pthread_mutex_lock。
image.png

于是std::mutex::lock()成功返回了。
image.png

所以,程序运行没有阻塞。
下面,在代码里,创建一个子线程:

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

再编译运行,神奇的事情发生了,阻塞住了。


image.png

综上说明,std::mutex确实是不支持在同一个thread里递归加锁的。但是在Linux里,程序运行时判断了一个条件,然后令std::mutex::lock()直接成功返回了,根本没有调用pthread_mutex_lock。
那么__gthread_active_p()是动态判断还是静态判断?是判断进程中有没有多个线程吗?即,这个函数是不是判断出,当前进程里只有一个主线程在运行,就会返回0?
回到最开始的代码,编译这段代码,但是强制链接pthread库。神奇的事情又发生了:


image.png

综上猜测,如果程序运行时没有加载pthread库,__gthread_active_p()就会返回0,不会调用pthread_mutex_lock。否则,就要老老实实地调用pthread_mutex_lock,即使现在只有一个主线程在运行。
第二次加锁会阻塞,是符合预期的。但是VS2017里居然报错……Windows嘛,你们开心就好。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容