本文系转载,著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

作者: 宋宝华

来源: 微信公众号linux阅码场(id: linuxdev)


竞态无所不在

首先我们要理解竞态(race condition)无所不在,哪怕是对一个全局变量做++的加1动作。

a=0
a++;

a++这句话,会被翻译为多条指令:

ldr     r3, [r3, #0] 
adds    r2, r3, #1
str     r2, [r3, #0] 

它会先读(ldr),再修改(add),再写(str),是一个典型的读-修改-写(RMW)序列。a++在硬件上不是原子的!

假设2个线程(或者1个线程1个中断)“同时”做a++,因为加了2次,理论上a应该是等于2,但是结果a可能只是等于1,原因很简单:

假设第2个线程,在第一个线程做完读(LDR)之后,抢入率先做完a++,显然这个时候a=1,但是由于第一个线程在ldr指令里面已经读到了a=0,第1个线程在第2个线程做完a++后,继续做++还是会在0的基础上面加(只需要执行add和str指令了),所以导致第1个线程再++后,a还是等于1.

解决这样的race condition,我们需要把2个线程的a++的读-修改-写序列,串行化,彼此排他化。

也就是把这种交错的RMW:

变成这种先后发生的RMW:

这样第2个序列可以读到1,并且在1的基础上加1,保证结果是2。

LDREX和STREX

ARM V7之后的LDREX、STREX指令可以解决这个问题。它保证2个读-修改-写序列有交叉的时候,只有1个可以写成功,另外一个则再次尝试。

比如下面这个序列,R用的LDREX,W用的STREX,则只有第一个线程的STREX可以成功,而第二个的W(STREX)会失败:

类似如下:

那么,这个执行strex失败的线程2,会把第一条的LDREX指令重新执行一次:

STREX指令,除了把寄存器的值写入一个地址以外,还可以返回这次写是否成功。

**STREXEQ r0, r1, [LockAddr] **

上述指令把r1写入地址LockAddr,如果写入成功,则r0=0,否则r0不等于0。如果r0不等于0,证明写入失败,那么需要重新来ldrex,重新来修改和写。官方解释如下:

The STREX instruction performs a conditionalstore of a word to memory. If the exclusive monitor(s) permit thestore, the operation updates the memory location and returns the value0 in the destination register, indicating that the operation succeeded.If the exclusive monitor(s) do not permit the store, the operationdoes not update the memory location and returns the value 1 in thedestination register. This makes it possible to implement conditionalexecution paths based on the success or failure of the memory operation.For example, STREX R2, R1, [R0] performs a Store-Exclusiveoperation to the address in R0, conditionallystoring the value from R1 and indicating successor failure in R2.

类似如下流程:

当两个LDREX,STREX序列交错的时候,谁先STREX,谁成功,第2个STREX失败,类似:

所以谁先LDREX不是重点,重点是谁先STREX谁成功,后STREX的重新来LDREX。

更多精彩更新中……欢迎关注微信公众号:linux阅码场(id: linuxdev)

宋宝华:关于ARM Linux原子操作的实现的更多相关文章

  1. 宋宝华: 关于Linux进程优先级数字混乱的彻底澄清

    宋宝华: 关于Linux进程优先级数字混乱的彻底澄清 原创: 宋宝华 Linux阅码场 9月20日 https://mp.weixin.qq.com/s/44Gamu17Vkl77OGV2KkRmQ ...

  2. 宋宝华:Linux设备驱动框架里的设计模式之——模板方法(Template Method)

    本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 前言 <设计模式>这本经典 ...

  3. 宋宝华: Linux内核编程广泛使用的前向声明(Forward Declaration)

    本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者:宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 前向声明 编程定律 先强调一点:在一切可 ...

  4. 宋宝华:Docker 最初的2小时(Docker从入门到入门)

    本文系转载,著作权归作者所有. 商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 最初的2小时,你会爱上Docker, ...

  5. 宋宝华:关于Ftrace的一个完整案例

    本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) Ftrace简介 Ftrace是Lin ...

  6. 《Linux设备驱动开发详解(第3版)》(即《Linux设备驱动开发详解:基于最新的Linux 4.0内核》)--宋宝华

    http://blog.csdn.net/21cnbao/article/details/45322629

  7. Linux设备驱动详解 宋宝华 硬件基础

    处理器 存储器 接口与总线 I2C时序 SPI总线时序 以太网

  8. 宋宝华:关于Ftrace的一个完整案例【转】

    Ftrace简介 Ftrace是Linux进行代码级实践分析最有效的工具之一,比如我们进行一个系统调用,出来的时间过长,我们想知道时间花哪里去了,利用Ftrace就可以追踪到一级级的时间分布. Ftr ...

  9. 宋宝华:Docker 最初的2小时(Docker从入门到入门)【转】

    最初的2小时,你会爱上Docker,对原理和使用流程有个最基本的理解,避免满世界无头苍蝇式找资料.本人反对暴风骤雨式多管齐下狂轰滥炸的学习方式,提倡迭代学习法,就是先知道怎么玩,有个感性认识,再深入学 ...

随机推荐

  1. CPU爆满后的无助感

    告警 晚七点刚好上地铁,握在手里的手机震动了好几下,根据震动这几下的手感已经判断出这是钉钉在告警了,十有八九就是线上的问题,通过Zabbix监控的一台线上服务器已经五分钟不可达,这应该不会是网络网络问 ...

  2. vue-music 跨域获取QQ音乐歌曲播放源

    这个问题困扰了我很久,一直获取不到正确的播放源,qq对这块限制更加严格了 按照之前老师在视频中的写法,已经不能获取到播放源了 下面来分析一下正确的播放源url:http://dl.stream.qqm ...

  3. fenby C语言 P12

    条件语句的嵌套 注意格式对齐 #include <stdio.h> int main(){ int score=67; if(score<=100&&score> ...

  4. Java设计模式_七大原则

    简介 单一职责原则.对类来说,即一个类应该只负责一项职责. 开闭原则.对扩展开放,对修改关闭.在程序需要进行扩展的时候,不能去修改原有代码,使用接口和抽象类实现一个热插拔的效果. 里氏替换原则.任何基 ...

  5. SpringCloud之Hystrix断路器(六)

    整合Hystrix order-service pom.xml         <dependency> <groupId>org.springframework.cloud& ...

  6. 通俗地说逻辑回归【Logistic regression】算法(一)

    在说逻辑回归前,还是得提一提他的兄弟,线性回归.在某些地方,逻辑回归算法和线性回归算法是类似的.但它和线性回归最大的不同在于,逻辑回归是作用是分类的. 还记得之前说的吗,线性回归其实就是求出一条拟合空 ...

  7. 关于RocketMQ消息消费与重平衡的一些问题探讨

    其实最好的学习方式就是互相交流,最近也有跟网友讨论了一些关于 RocketMQ 消息拉取与重平衡的问题,我姑且在这里写下我的一些总结. ## 关于 push 模式下的消息循环拉取问题 之前发表了一篇关 ...

  8. 《Effective Java》 读书笔记(五)使用依赖注入取代原本的资源依赖

    相信接触过Spring的同学,对于依赖注入并不陌生. 刚开始在听说这个名字的时候,一直不明白到底什么叫依赖注入,后来才发现,依赖注入一直都存在我们日常代码中,只是我们没有刻意的把它提出来,然后再取这样 ...

  9. 如何让elemengUI中的表格组件相同内容的单元格自动合并

    1. 前言 这两天在工作中遇到这样一个需求:将某个Excel中的数据在页面上以表格形式展示出来,并且尽量保持数据层级与Excel中一致.在原始Excel文件中,对每一行相同的数据都进行了合并,使得数据 ...

  10. 『题解』洛谷P5436 【XR-2】缘分

    Problem Portal Portal1:Luogu Description 一禅希望知道他和师父之间的缘分大小.可是如何才能知道呢? 一禅想了个办法,他先和师父约定一个正整数\(n\),接着他们 ...