Modern C++ std::mutex底层原理

前言

我时常有这样的疑问:

  1. std::mutex怎么就能保证后面的语句100%安全哪?
  2. CPU reordering就不会把这些语句重排到mutex前面执行?
  3. 而且各个CPU都是有L1、L2缓存的,如果mutex后面要访问的的变量在这些缓存中怎么办?

带着这些疑问我们先看看std::mutex是怎么实现的。

std::mutex::lock流程图

先给个图,再细说。

底层原理

先写个简单的cpp程序:

#include <iostream>       // std::cout
#include <thread>         // std::thread
#include <mutex>          // std::mutex, std::lock_guard, std::adopt_lockstd::mutex mtx;           // mutex for critical section
int total=0;void print_thread_id(int id) {mtx.lock();for(int i=0;i<10000;i++) total++;mtx.unlock();
}int main()
{print_thread_id(1);print_thread_id(2);std::cout<<"total="<<total<<std::endl;return 0;
}

我没起线程啊,只想看看std::mutex是怎么lock的, 这里调用print_thread_id两次也是故意的,因为第一次很多函数符号都没解决(函数@plt),遇到一个函数都要到ld里走一圈,很烦人。而第二次调用就用不着了。

在第二个print_thread_id上加断点,gdb中layout asm看汇编(也可以直接看glibc源码,实际源码有太多宏更不如汇编看的直接):

一路si(单步instruction执行),来到了关键指令:lock cmpxchg

 $r8正好执行我们定义的全局变量mtx, 从上个截图可以看到mtx结构中第一个member是int类型的__lock(看到名字也能盲猜这是mutex::lock的关键),而edi=1。

cmpxchg指令语法如下(请把cmos_lock看成mtx.__lock,  %edx为1):

 cmpxchg会原子的完成下面的IF+赋值,不会让别的线程看到中间状态。

 没被锁的情况下,destination(mtx.__lock)为0,accumulator($EAX)为0(pthread_mutex_lock+91 xor %eax,%eax使得eax的值为0),故ZF标志位被置为1,同时把source(1,pthread_mutex_lock+86 mov 1,%edi)存入mtx.__lock(表示锁上了)。

被别人锁的情况,请看下面的调试:

至于mtx.__lock会不会被各个CPU缓存,或者此指令后面的指令会不会被CPU重排,查了一些资料,也没弄100%明白,姑且先认为是吧。不然这么底层的东西早就造成大量问题了。

附上一些讨论:

concurrency - Is x86 CMPXCHG atomic, if so why does it need LOCK? - Stack Overflowicon-default.png?t=N7T8https://stackoverflow.com/questions/27837731/is-x86-cmpxchg-atomic-if-so-why-does-it-need-lock

multithreading - Do locked instructions provide a barrier between weakly-ordered accesses? - Stack Overflowicon-default.png?t=N7T8https://stackoverflow.com/questions/50280857/do-locked-instructions-provide-a-barrier-between-weakly-ordered-accesses
https://heather.cs.ucdavis.edu/matloff/public_html/50/PLN/lock.pdficon-default.png?t=N7T8https://heather.cs.ucdavis.edu/matloff/public_html/50/PLN/lock.pdf

 如果此处发现mtx.__lock已经是1,也就是别人锁上了,则转系统调用202号(sys_futex)挂起当前线程。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/340846.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中央处理器CPU(1)----指令周期和微程序

前言&#xff1a;由于期末复习计算机组成效率太慢所以抽时间写一下文章总结一下思路&#xff0c;理解不是很深&#xff0c;欢迎各位不吝赐教。 由于时间不是很充分&#xff0c;所以有些考点由于我们不考试&#xff0c;一笔带过了。 我这是期末复习总结&#xff0c;不是考研知识…

开源C语言库Melon:数据恢复算法

本文讲述开源C语言库Melon中的里德所罗门纠错码的使用。 关于 Melon 库&#xff0c;这是一个开源的 C 语言库&#xff0c;它具有&#xff1a;开箱即用、无第三方依赖、安装部署简单、中英文文档齐全等优势。 Github repo 简介 里德所罗门编码是一种纠错码技术&#xff0c;…

如何理解线程池中的参数设计

如何理解线程池中的参数设计 你的线程池的参数怎么配置&#xff1f;线程数量设置多少合理&#xff1f;如何确定一个线程池中的人物已经完成了为什么不建议使用java自带的Executors创建线程池线程池里面的阻塞队列设置多少合理&#xff1f; 考察&#xff1a;了解你对技术的掌握…

k8s-调度 13

调度器通过 kubernetes 的 watch 机制来发现集群中新创建且尚未被调度到 Node 上的 Pod。调度器会将发现的每一个未调度的 Pod 调度到一个合适的 Node 上来运行。 kube-scheduler 是 Kubernetes 集群的默认调度器&#xff0c;并且是集群控制面的一部分。 如果你真的希望或者有…

printk的使用与理解

文章目录 一、理清printk二、printk的使用三、printk的打印级别1、基本解释2、详细解释3、如何修改console_loglevel、default_message_loglevel、minimum_console_loglevel、default_console_loglevel的值 四、printk的输出地方五、其它 一、理清printk printk如何使用&#…

讲讲关于跨域的问题,什么是跨域?怎么办?

文章目录 什么是跨域如果非同源&#xff0c;共有三种行为受到限浏览器客户端和向服务器跨域请求的判定流程 跨域问题演示参考 以下内容为我结合他人知识进行的自我总结, 如有错误欢迎指出~ 什么是跨域 跨域就是不同的域名下的资源访问&#xff0c;会被浏览器的本地安全策略阻…

【Python学习】Python学习13-日期和时间

目录 【Python学习】Python学习13-日期和时间 前言通过time 获取时间戳时间元组获取当前时间&#xff0c;格式化时间格式化时间转换python中时间日期格式化符号获取日历Time 模块日历&#xff08;Calendar&#xff09;模块其他模块参考 文章所属专区 Python学习 前言 本章节主…

开源知识库工具推荐:低成本搭建知识库

在信息爆炸的时代&#xff0c;企业和个体对知识的存储和管理需求日益增强。开源知识库工具因其开源、免费、高效的特性&#xff0c;成为了众多组织和个人的首选。如果你正在寻找一款优秀的开源知识库工具&#xff0c;本文将为你推荐三款性能优异的产品&#xff0c;感兴趣就往下…

小马识途:十个营销故事 启发营销思路

在营销过程中&#xff0c;优势是相对的&#xff0c;只有凭借着客观的营销环境创造优势才能够取胜市场。在企业营销中&#xff0c;狗猛酒酸的案例比比皆是。接下来&#xff0c;就与小马识途一起来看看十个经典的营销故事吧&#xff01; 一、摩托车公司 有家德国摩托车公司&…

Ubuntu系统中指定端口防火墙状态查询与操作

浏览器访问&#xff1a; 如果遇到如山图所示的情况&#xff0c;既有可能是防火墙的问题。具体解决方案参照如下&#xff1a; 1.指定端口的防火墙状态查询 &#xff08;1&#xff09;查询命令 sudo ufw status | grep 8081/tcp #其中8081为要查询的端口号 如果端口是打开的…

【vue3中状态管理工具pinia的使用】pinia状态一(state)

1、安装 yarn add pinia//或者//npm install pinia2、在main.js中引入store // 引入piniaimport { createPinia } from piniaconst pinia createPinia()// 使用piniaapp.use(pinia)3、创建一个Store 在项目根目录的 src文件夹 —— 创建store文件夹 —— 创建 index.js 文件 …

VTK开发调试环境下载(VTK开发环境一步到位直接开发,无需自己配置编译 VS2017+Qt5.12.10+VTK)

一、无与伦比的优势 直接下载代码就可以调试的VTK代码仓库。 二、资源制作原理 这个资源根据VTK源码 编译出动态库文件 pdb lib dll 文件&#xff08; x64 debug &#xff09; 并将这两者同时放在一个代码仓库里&#xff0c;下载就能用。 三、使用方法&#xff08;vtk-so…