聊聊CPU的LOCK指令
本文转载自聊聊CPU的LOCK指令
导语
在多线程操作中,可能最经常被提起的就是数据的可见性、原子性、有序性。不管是硬件方面、软件方面都在这三方面做了很足的工作,才能保证程序的正常运行。
之前发表过一篇文章聊聊缓存一致性协议 如果感兴趣的话可以去阅读一下,里面谈到了缓存一致性的实现和处理过程,读完之后可以仔细去细想一下缓存一致性协议到底解决了什么问题。个人理解缓存一致性协议解决了CPU层面的可见性和一致性问题,阅读到这里可以在这里停下来,仔细回想一下缓存一致性的原理,它通过监听共享总线上消息,对自己缓存中的数据修改不同的状态,来保证数据的一致性,对自己缓存中的数据失效后,下次读取会从主存中直接读取最新的数据 ,可以保证可见性,同时保证各缓存中的数据是一致的。
软件的并发编程一样,其实除了可见性、有序性,在计算机指令在执行的过程中,CPU通过不停地切换线程执行,给每个线程分配CPU时间片来实现多线程机制,一定也会存在原子性问题,在计算机层面是怎么解决原子性问题的,这就我们今天要聊的LOCK#指令,有时也被我们称为总线锁。
LOCK指令作用
在Intel 64 and IA-32 Architectures Software Developer’s Manual 中的章节LOCK—Assert LOCK# Signal Prefix 中给出LOCK指令的详细解释

大至翻译之后的意思如下
在CPU的LOCK信号被声明之后,在此期随同执行的指令会转换成原子指令。在多处理器环境中,LOCK信号确保,在此信号被声明之后,处理器独占使用任何共享内存。
在不大多数IA-32和Inter64位处理器中,锁可能在没有LOCK#信号的时情况下发生。请参阅下面的“IA32体系结构兼容性”部分的详细内容。
LOCK前缀只能预加在以下指令前面,并且只能加在这些形式的指令前面,其中目标操作数是内存操作数:
add、adc、and、btc、btr、bts、cmpxchg、cmpxch8b,cmpxchg16b,dec,inc,neg,not,or,sbb,sub,xor,xadd和xchg。如果LOCK前缀用上述列表中的指令并且源操作数是内存操作数(也就是指令没有对内存进行写操作),可能会出现未定义的
操作码异常(ud)。如果锁前缀与任何不在上面列表中的指令一起使用,也将生成未定义的操作码异常。
xchg指令不管有没有声明LOCK前缀,总是会声明LOCK信号。锁定前缀通常与BTS指令一起使用,在共享内存环境中,以对内存地址执行
读-修改-写操作。锁定前缀的完整性不受内存字段对齐的影响。对于任意未对齐的字段,可以观察到内存锁定。
此指令的操作在非64位模式和64位模式下是相同的。
从P6系列处理器开始,当使用 LOCK 指令访问的内存已经被处理器加载到缓存中时,LOCK# 信号通常不会断言。取而代之的是,只锁定处理器的缓存。在这里处理器的缓存一致性机制确保对内存进行的操作是原子性的。请参见“锁定操作对内部处理器缓存的影响”,在Intel64和IA-32体系结构软件开发人员手册第3A卷第8章中,有关锁定缓存的详细信息。
大致翻译差不多如上,核心意思主要说明LOCK指令在声明之后通过锁定总线,独占共享内存,通过一种排它的思想确保当前对内存操作的只有一个线程,然后确定在这段声明期间指令执行不会被打断,来保证其原子性。
处理器如何实现原子操作
首先处理器会保证基本的内存操作的原子性,比如从内存读取或者写入一个字节是原子的,但对于读-改-写、或者是其它复杂的内存操作是不能保证其原子性的,又比如跨总线宽度、跨多个缓存行和夸页表的访问,这时候需要处理器提供总线锁和缓存锁两个机制来保证复杂的内存操作原子性
总线锁
LOCK#信号就是我们经常说到的总线锁,处理器使用LOCK#信号达到锁定总线,来解决原子性问题,当一个处理器往总线上输出LOCK#信号时,其它处理器的请求将被阻塞,此时该处理器此时独占共享内存。
总线锁这种做法锁定的范围太大了,导致CPU利用率急剧下降,因为使用LOCK#是把CPU和内存之间的通信锁住了,这使得锁定时期间,其它处理器不能操作其内存地址的数据 ,所以总线锁的开销比较大。
缓存锁
如果访问的内存区域已经缓存在处理器的缓存行中,P6系统和之后系列的处理器则不会声明LOCK#信号,它会对CPU的缓存中的缓存行进行锁定,在锁定期间,其它 CPU 不能同时缓存此数据,在修改之后,通过缓存一致性协议来保证修改的原子性,这个操作被称为“缓存锁”
什么情况下使用总线锁(LOCK#)
当操作的数据不能被缓存在处理器内部,或操作的数据跨多个缓存行时,也会使用总线锁
因为从P6系列处理器开始才有缓存锁,所以对于早些处理器是不支持缓存锁定的,也会使用总线锁
有些指令自带总线锁
BTS、BTR、BTC 、XADD、CMPXCHG、ADD、OR等,这些指令操作的内存区域就会加锁,导致其它处理器不能同时访问它。
在上面指令中的CMPXCHG就是JAVA里面CAS底层常用的指令,这个指令在执行的时候,会自动加总线锁保,导致其它 处理器不能同时访问,证其原子性。
LOCK#作用总结
- 锁总线,其它CPU对内存的读写请求都会被阻塞,直到锁释放,因为锁总线的开销比较大,后来的处理器都采用锁缓存替代锁总线,在无法使用缓存锁的时候会降级使用总线锁
- lock期间的写操作会回写已修改的数据到主内存,同时通过缓存一致性协议让其它CPU相关缓存行失效
写在最后
总线锁、缓存锁可以保证原子性,缓存一致性协议可以保证可见性,那么JAVA中的内存模型,它做了些什么?下一篇聊聊JAVA中的内存模型(JMM)聊聊JMM
聊聊CPU的LOCK指令的更多相关文章
- 【操作系统之十一】任务队列、CPU Load、指令乱序、指令屏障
一.CPU Loadcpu load是对使用或者等待cpu进程的统计(数量的累加):每一个使用(running)或者等待(runnable)CPU的进程,都会使load值+1;每一个结束的进程,都会使 ...
- 关于缓存一致性协议、MESI、StoreBuffer、InvalidateQueue、内存屏障、Lock指令和JMM的那点事
前言 事情是这样的,一位读者看了我的一篇文章,不认同我文章里面的观点,于是有了下面的交流. 可能是我发的那个狗头的表情,让这位读者认为我不尊重他.于是,这位读者一气之下把我删掉了,在删好友之前,还叫我 ...
- 深入设计电子计算器(一)——CPU框架及指令集设计
版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/8278418.html 作者:窗户 Q ...
- 使用logisim搭建单周期CPU与添加指令
使用logisim搭建单周期CPU与添加指令 搭建 总设计 借用高老板的图,我们只需要分别做出PC.NPC.IM.RF.EXT.ALU.DM.Controller模块即可,再按图连线,最后进行控制信号 ...
- CPU结构与指令执行过程简介
CPU(Central Processing Unit)是计算机中进行算术和逻辑计算处理指令的主要部件. CPU结构 CPU由通用寄存器组,运算器,控制器和数据通路等部件组成. 寄存器包括 数据寄存器 ...
- CPU流水线与指令乱序执行
青蛙见了蜈蚣,好奇地问:"蜈蚣大哥,我很好奇,你那么多条腿,走路的时候先迈哪一条啊?" 蜈蚣听后说:"青蛙老弟,我一直就这么走路,从没想过先迈哪一条腿,等我想一想再回答你 ...
- 使用CPU的AVX指令
arch:AVX 很抱歉GCC还不行……有……倒是 但是不是这么写的 我忘记了……官网上有 http://www.oschina.net/news/66980/kreogist-0-9
- java并发编程知识点备忘
最近有在回顾这方面的知识,稍微进行一些整理和归纳防止看了就忘记. 会随着进度不断更新内容,比较零散但尽量做的覆盖广一点. 如有错误烦请指正~ java线程状态图 线程活跃性问题 死锁 饥饿 活锁 饥饿 ...
- 并发编程之 Java 内存模型 + volatile 关键字 + Happen-Before 规则
前言 楼主这个标题其实有一种作死的味道,为什么呢,这三个东西其实可以分开为三篇文章来写,但是,楼主认为这三个东西又都是高度相关的,应当在一个知识点中.在一次学习中去理解这些东西.才能更好的理解 Jav ...
随机推荐
- kubenetes 相关命令(转载)
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/xingwangc2014/article/details/51204224好久没写博客了,前段时间公 ...
- Centos搭建Hive
Centos搭建Hive 一.Hive简介 二.安装Hive 2.1hive下载 2.2上传解压 2.3配置hive相关的环境变量 三.Mysql 3.1安装mysql connector 3.2 将 ...
- linux shell 条件判断if else, if elif else....
在linux的shell中 if 语句通过关系运算符判断表达式的真假来决定执行哪个分支.Shell 有三种 if ... else 语句: if ... fi 语句: if ... else ... ...
- ifndef /define/ endif 作用和用法
问题:ifndef/define/endif"主要目的是防止头文件的重复包含和编译====================================================== ...
- oss-server 小型对象存储系统
oss-server 项目介绍 oss-server是针对项目开发时提供的小型对象存储系统,开发者在针对文件上传时业务剥离,同时方便文件迁移,为满足单个项目,多个系统的情况下,提供统一的oss服务 o ...
- python实现经典排序算法
以下排序算法最终结果都默认为升序排列,实现简单,没有考虑特殊情况,实现仅表达了算法的基本思想. 冒泡排序 内层循环中相邻的元素被依次比较,内层循环第一次结束后会将最大的元素移到序列最右边,第二次结束后 ...
- Java安全之jar包调试技巧
Java安全之jar包调试技巧 调试程序 首先还是创建一个工程,将jar包导入进来 调试模式的参数 启动中需要加入特定参数才能使用debug模式,并且需要开放调试端口 JDK5-8: -agentli ...
- 2020 CCPC-Wannafly Winter Camp Day2
2020 CCPC-Wannafly Winter Camp Day2 A 托米的字符串 虽然每个子串出现的概率是相同的,但是同一长度的子串个数是不同的,所以要分别处理.计算出某一长度的情况下,元音字 ...
- 配置VS2013 + opencv 2.4.10
其实我内心是极力反对装这么老的版本的,但是要交课堂作业~~好无奈 [注] : 如果按照本文配置不成功,可以试一下其他博客里面的配置(多试一试总能成功的) https://jingyan.baidu.c ...
- Second My Problem First HDU - 3706 单调队列
单调队列 单调队列是指一个队列内部的元素具有严格单调性的一种数据结构,分为单调递增队列和单调递减队列. 单调队列满足两个性质 1.单调队列必须满足从队头到队尾的严格单调性. 2.排在队列前面的比排在队 ...