宋宝华:关于ARM Linux原子操作的实现
本文系转载,著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
作者: 宋宝华
来源: 微信公众号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原子操作的实现的更多相关文章
- 宋宝华: 关于Linux进程优先级数字混乱的彻底澄清
宋宝华: 关于Linux进程优先级数字混乱的彻底澄清 原创: 宋宝华 Linux阅码场 9月20日 https://mp.weixin.qq.com/s/44Gamu17Vkl77OGV2KkRmQ ...
- 宋宝华:Linux设备驱动框架里的设计模式之——模板方法(Template Method)
本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 前言 <设计模式>这本经典 ...
- 宋宝华: Linux内核编程广泛使用的前向声明(Forward Declaration)
本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者:宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 前向声明 编程定律 先强调一点:在一切可 ...
- 宋宝华:Docker 最初的2小时(Docker从入门到入门)
本文系转载,著作权归作者所有. 商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 最初的2小时,你会爱上Docker, ...
- 宋宝华:关于Ftrace的一个完整案例
本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) Ftrace简介 Ftrace是Lin ...
- 《Linux设备驱动开发详解(第3版)》(即《Linux设备驱动开发详解:基于最新的Linux 4.0内核》)--宋宝华
http://blog.csdn.net/21cnbao/article/details/45322629
- Linux设备驱动详解 宋宝华 硬件基础
处理器 存储器 接口与总线 I2C时序 SPI总线时序 以太网
- 宋宝华:关于Ftrace的一个完整案例【转】
Ftrace简介 Ftrace是Linux进行代码级实践分析最有效的工具之一,比如我们进行一个系统调用,出来的时间过长,我们想知道时间花哪里去了,利用Ftrace就可以追踪到一级级的时间分布. Ftr ...
- 宋宝华:Docker 最初的2小时(Docker从入门到入门)【转】
最初的2小时,你会爱上Docker,对原理和使用流程有个最基本的理解,避免满世界无头苍蝇式找资料.本人反对暴风骤雨式多管齐下狂轰滥炸的学习方式,提倡迭代学习法,就是先知道怎么玩,有个感性认识,再深入学 ...
随机推荐
- Android开发高手课NOTE
最近学习了极客时间的<Android开发高手课>很有收获,记录总结一下. 欢迎学习老师的专栏:Android开发高手课 内存优化 卡顿的原因 频繁 GC 造成卡顿.物理内存不足时系统会触发 ...
- 封装自己通用的 增删改查的方法 By EF
封装自己的通用CURD By EF using System; using System.Collections.Generic; using System.Data.Entity; using Sy ...
- Unity常用协程功能封装
# 1.前言unity开发过程中,经常用到一些特定的协程功能,比如延时触发.等待触发.重复操作等.unity自带Invoke以及InvokeRepeating方法,但这些方法均采用反射机制,性能消耗, ...
- 【阿里云IoT+YF3300】8.物联网设备用户脚本开发
除了我们必须熟悉的网页脚本,比如JavaScript.其实在工业自动化中,组态软件是必备脚本的,只是有的脚本语言风格类似C或类似Basic而已.比如昆仑通泰的组态屏中的组态软件.通过安装组态软件可以简 ...
- Chrome插件开发(三)
在日常工作中,我们可能经常需要在手机端测试我们所做的页面,如果每次在手机端测试都手输网址,网址短的还好,如果长的网址也需要一个字母一个字母去敲,那无疑是一场噩梦,试想我们有一个工具只需要点击一个按钮就 ...
- activeMQ 安装及启动异常处理
一.环境: [root@centos_6 ~]# cat /etc/system-release CentOS release 6.5 (Final) [root@centos_6 ~]# uname ...
- 中级前端必备知识点(2.5w+月薪)进阶 (分享知乎 : 平酱的填坑札记 关注专栏 用户:安大虎)
前端已经不再是5年前刚开始火爆时候的那种html+css+js+jquery的趋势了,现在需要你完全了解前端开发的同时,还要具备将上线.持续化.闭环.自动化.语义化.封装......等概念熟练运用到工 ...
- 程序员这十个java题你都会吗?
前言 不论你是职场新人还是步入职场N年的职场新人大哥大~当然这个N<3~,我能担保你答不对这十个题~不要问我为什么这么自信~,这些个题还是"有水平"的javase的基础题,传 ...
- 第一个appium测试用例
from time import sleep from appium import webdriver import pytest class TestXueqiu: user_profile_id ...
- MySQL8.0 redo日志系统优化
背景 现在主流的数据库系统的故障恢复逻辑都是基于经典的ARIES协议,也就是基于undo日志+redo日志的来进行故障恢复.redo日志是物理日志,一般采用WAL(Write-Ahead-Loggin ...