宋宝华:关于ARM Linux原子操作的实现

宋宝华:关于ARM Linux原子操作的实现本文系转载,著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。作者: 宋宝华来源: 微信公众号linux阅码场(id: lin

大家好,欢迎来到IT知识分享网。

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

作者: 宋宝华

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

宋宝华:关于ARM Linux原子操作的实现

竞态无所不在

首先我们要理解竞态(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,原因很简单:

宋宝华:关于ARM Linux原子操作的实现

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

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

也就是把这种交错的RMW:

宋宝华:关于ARM Linux原子操作的实现

变成这种先后发生的RMW:

宋宝华:关于ARM Linux原子操作的实现

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

LDREX和STREX

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

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

宋宝华:关于ARM Linux原子操作的实现

类似如下:

宋宝华:关于ARM Linux原子操作的实现

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

宋宝华:关于ARM Linux原子操作的实现

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.

类似如下流程:

宋宝华:关于ARM Linux原子操作的实现

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

宋宝华:关于ARM Linux原子操作的实现

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

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

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/73310.html

(0)
上一篇 2024-07-05 17:33
下一篇 2024-07-06 18:00

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信