我学习了大卫A. Patterson,并在第254页的Elaboration中有以下代码
以下是书籍内容和相关代码:
虽然上面的代码实现了原子交换,但下面的代码将更有效地在寄存器x20中的位置获取锁,其中0的值表示锁空闲,1表示获取锁:
addi x12, x0, 1
// copy locked value
again: lr.d x10, (x20)
// load-reserved to read lock
bne x10, x0, again
// check if it is 0 yet
sc.d x11, x12, (x20)
// attempt to store new value
bne x11, x0, again
// branch if store fails
加锁后由**(基于)原始更改
由于load-reserved返回初始值,而store-conditional只有在成功时才返回0,因此以下序列在x20的内容指定的内存位置上实现**原子交换:
again:lr.d x10, (x20)
// load-reserved
sc.d x11, x23, (x20)
// store-conditional
bne x11, x0, again
// branch if store fails
addi x23, x10, 0
// put loaded value in x23
1-书上说通过addi x12, x0, 1 // copy locked value
将锁添加到代码中“更有效”,我不知道它在哪里
2-我认为这种锁无法避免基于“缓存线”硬件设计的“虚假故障”,对吗?
1条答案
按热度按时间rnmwe5a21#
我认为作者的意思是比
do{}while(x20->exchange(1) == 0)
更少的指令,这是使用他们的交换函数来获取自旋锁的明显方式。(这是他们的循环所做的。在C++术语中,它有点像do{}while(! lock.cas_weak(0, 1));
,但他们关于asm效率的观点是特定于LL/SC的)当负载看到非零值时,根本不存储也可能是有益的。(所以这个核心在另一个核心向它存储了
0
之后才能对缓存行做任何有用的事情时,它不会独占缓存行的所有权。)但是我不确定lr.d
是否会在预期SC时尝试获得独占所有权(发送RFO =读取所有权)。如果比较失败,它至少不会弄脏该高速缓存行,因此不必写回它。这也可以减少多个线程等待锁的活锁问题,所有线程都运行这个循环。
有关具有多个旋转、只读与原子RMW访问参见通过内联汇编的内存操作周围的锁(x86,只有单指令CAS_strong,而不是LL/SC)。
1.正确,您无法避免LL/SC指令的伪故障。