宋宝华:关于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,对原理和使用流程有个最基本的理解,避免满世界无头苍蝇式找资料.本人反对暴风骤雨式多管齐下狂轰滥炸的学习方式,提倡迭代学习法,就是先知道怎么玩,有个感性认识,再深入学 ...
随机推荐
- vue.js 使用 vue-router 修改页面标题
module.exports = { name: 'myComponent', data: {} route{ data: function(){ document.title = "页面标 ...
- datatable dataset
简单讲解一下dataset和datatable,以excel对比,dataset相当于一个excel文件,datatable相当于excel的一张表格.datatable可以单独应用,dataset里 ...
- Dotween 应用
dotween是做缓动比较简单实用的插件,下面就使用经验进行浅谈 1)通用方法:如下图官网截图所示,如果看不懂可以跳过,这是一个通用方法,前两个参数为委托类型,可以用lambda表达式,也可以直接写成 ...
- js更高文档的样式
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- fenby C语言 P17
for姐姐 dowhile妹妹 while for(循环变量赋初值,循环条件,循环变量自加) #include <stdio.h> int main(){ int sum=0,i; for ...
- SpringBoot整合Mybatisplus3.x之CRUD(一)
pom.xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId& ...
- java 时间戳 、时间差计算(秒、分钟、小时、天数、月份、年)
以下代码就是时间差计算(秒.分钟.小时.天数.月份.年) package me.zhengjie; import java.text.ParseException; import java.text. ...
- Linux常见命令之文件处理命令
ls命令 ls(选项)(参数) 选项 -a:显示所有档案及目录(ls内定将档案名或目录名称为“.”的视为影藏,不会列出): -A:显示除影藏文件“.”和“..”以外的所有文件列表: -C:多列显示输出 ...
- Java基础01-集合1、泛型
集合.泛型 第一章:集合1 1. 什么是集合 定义:在Java中,集合是一种可以存储多个数据的容器. 代码: ArrayList<String> list = new ArrayList& ...
- Android 禁止截屏、录屏 — 解决PopupWindow无法禁止录屏问题
项目开发中,为了用户信息的安全,会有禁止页面被截屏.录屏的需求. 这类资料,在网上有很多,一般都是通过设置Activity的Flag解决,如: //禁止页面被截屏.录屏 getWindow().add ...