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

作者: 宋宝华

来源: 微信公众号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. scrollWidth、clientWidth 和 offsetWidth

    scrollWidth:对象的实际内容宽度,不包括边线宽度,会随对象中内容超过可视区而变大. clientWidth:对象内容的可视区的宽度,不包括边线宽度,会随对象显示大小的变化而变化. offse ...

  2. Java连接MySQL简单步骤及常见问题解析

    这篇文章跟读者们介绍Java语言如何连接到MySQL数据库相关操作,及FAQ(Frequently Asked Questions)介绍. 选择工具和准备数据集 IDE:Eclipse 数据库:使用的 ...

  3. JavaFX简介和Scene Builder工具的安装使用简易教程

    JavaFX概述和简介 富互联网应用是那些提供与Web应用程序类似的功能,并可作为桌面应用程序体验的应用.与用户的正常网络应用程序相比,它们提供更好的视觉体验.这些应用程序可作为浏览器插件或作为虚拟机 ...

  4. vscode debug golang

    基础的配置网上的教程很多,这里只是记录自己碰到的坑. 官方文档 https://code.visualstudio.com/docs/editor/debugging#_launch-configur ...

  5. 【TCP/IP网络编程】:03地址族与数据序列

    上一篇文章介绍了套接字的创建过程,这篇文章主要讨论分配给套接字的IP地址和端口号的相关知识. IP地址和端口号 IP(Internet Protocol,网络协议)地址是收发网络数据而分配给计算机的值 ...

  6. 描述Linux发行版的系统目录名称命名规则以及用途

    linux各种发行版都遵循LSB(Linux Stadards Base)规则,使用一致的相关的基础目录名称,使用根目录系统结构(root filesystem),使用FHS(Files Hierar ...

  7. VLAN的 基本用法与配置

    需求:在一家小型企业中,所有员工都使用一台交换机,老板为了避免员工私下通信,将他们分配了不同网段,但偶尔还是会发现,有些员工会自行修改网段和别人通信.如果你是这家企业的网络工程师,你该如何处理? 1. ...

  8. mysql双主互为主从配置

    在使用双主互为主从的模式前提是互为主从的两个数据库,表的主键必须是自增的. 环境不多说了 ,多台mysql单实例或单台多实例都可以.多实例的配置请参考:https://www.cnblogs.com/ ...

  9. Python 基础之re 模块

    Python 基础之大话 re 在使用re模块中主要会用到一下几个方法: re.match() #从头匹配一个字符串 re.search() #浏览全部字符串,匹配第一个符合规则的字符串 re.fin ...

  10. Java基础语法07-面向对象-多态

    抽象类 抽象方法 : 没有方法体的方法. 抽象类:被abstract所修饰的类. 抽象类的语法格式: [权限修饰符] abstract class 类名{ }[权限修饰符] abstract clas ...