LoadLinked/StoreConditional (LL/SC)
理解MIPS指令集中的ll (load linked) 和 sc
你用ll指令读取一个内存中的数据并存到一个寄存器,然后在寄存器修改(或不)这个值,随后用sc指令将它写入到同样的(原来的)位置。
而sc指令只在你修改寄存器中的值的期间,没有任何一个处理器改变它内存中的值 这种情况下,将值写入。
它同时需要(的副作用是)设置一个指示状态的变量来表明是否成功写入。(成功为1,失败为0) 当新的值成功地被写入了,那么可以认为这个线程在没有别的线程干涉的情况下完成了(一个值的)读-改-写过程。
如果失败了,接下来就取决于程序是要放弃这个操作还是再试一次了,不过至少它(ll&sc)不会生成一个隐性的(不被察觉的)竞争危害。
LL(Load Linked,链接加载)以及SC(Store Conditional,条件存储)
LL 指令的功能是从内存中读取一个字,以实现接下来的 RMW(Read-Modify-Write) 操作;
SC 指令的功能是向内存中写入一个字,以完成前面的 RMW 操作。
LL/SC 指令的独特之处在于,它们不是一个简单的内存读取/写入的函数,当使用 LL 指令从内存中读取一个字之后,
比如 LL d, off(b),处理器会记住 LL 指令的这次操作(会在 CPU 的寄存器中设置一个不可见的 bit 位),同时 LL 指令读取的地址 off(b) 也会保存在处理器的寄存器中。
接下来的 SC 指令,比如 SC t, off(b),会检查上次 LL 指令执行后的 RMW 操作是否是原子操作(即不存在其它对这个地址的操作),
如果是原子操作,则 t 的值将会被更新至内存中,同时 t 的值也会变为1,表示操作成功;
反之,如果 RMW 的操作不是原子操作(即存在其它对这个地址的访问冲突),则 t 的值不会被更新至内存中,且 t 的值也会变为0,表示操作失败。
SC 指令执行失败的原因有两种:
- 在 LL/SC 操作序列的过程中,发生了一个异常(或中断),这些异常(或中断)可能会打乱 RMW 操作的原子性。
- 在多核处理器中,一个核在进行 RMW 操作时,别的核试图对同样的地址也进行操作,这会导致 SC 指令执行的失败。
在IBM的那篇文章中,并没有说明SC是如何实现RMW是否有冲突的操作的。
在一般实现中,处理器有两个专门的域给LL和SC指令,即上文中的“不可见的bit位”以及保存ll操作地址的“寄存器”。
再LL之后,处理器会监测各种事件,当发生异常或者有别的处理器对该地址发了invalid请求时,会将不可见的bit位重置,从而导致后面的SC失败。
由于这样的bit位只有一位,存ll的寄存器也只有一个,因此,LL/SC无法实现嵌套,也即无法实现嵌套锁,这是程序员使用LL/SC所需要注意的。