LL和SC

多核处理器在执行并行访问时, 很可能会出现多个核同时访问共享资源的情况,操作系统通常采用锁的机制来防止一个核在访问共享资源时,该共享资源被其他核所改写。当某个共享资源被锁住时,只有获得这个锁的cpu核能够操作共享资源,其他试图访问这个共享资源的cpu核只能等待当前持有锁的cpu释放掉锁之后,才能获取锁去访问共享资源。为保护共享资源不被打扰,需要建立一个临界区域,临界区的操作称作原子操作。信号量是实现临界区的一个方法,信号量是一个并发运行的进程共享的内存区域,用来保证某些资源一次只能被一个进程使用。

每个原子代码段有下列结构:

wait(sem);
/* 做原子操作 */
signal(sem);

sem就是一个信号量,这个信号量有两个值,1表示信号量在使用中,等待;0表示信号量空闲,可以使用。进行原子操作之前,wait()判断sem的值,如果sem=1,等待sem=0。如果sem=0,把sem置1,然后执行原子操作。原子操作结束之后,signal()把sem清0。wait()函数的内部,也是这样的一个原子操作。

mips使用ll(链接加载)和sc(条件存储)两条指令实现信号量机制。使用它们可以对一个变量实现任意的读-修改-写序列(ll读,sc写)。这种指令序列并不保证所有操作的原子性,但是只有当这些指令序列的执行确实没有受到干扰,是原子操作的情况下才能成功完成。

ll : ll rt, offset(base) 从内存中加载一个word, 将处理器内部的一个不可见的硬件链接位置1,将加载指令的地址存储在寄存器LLAddr中。
sc : sc rt, offset(base) 检测上次ll指令执行后开始的读-修改-写序列是否真的没有受到任何干扰(不可见的硬件链接位是1)。如果操作是原子性的,rt寄存器的值就会存储到相应的内存地址,同时“真”值1返回到rt寄存器,设置不可见的硬件链接位为0。如果读-修改-写序列受到干扰(不可见的硬件链接位是0),操作不是原子性的,内存中的数据会保持不变,设置rt寄存器的值为0。
LLAddr : 寄存器,用于存储最近运行的链接加载操作的物理地址,。

下面是wait(sem)的实现:

wait :
    /* 获取信号量sem的地址,存到t0寄存器 */
    la    t0, sem
TrayAgain :
    /* 取sem的值,存到t1寄存器,设置链接位为1,把sem的值存到LLAddr寄存器 */
    ll    t1, 0(t0)
    /* 如果信号量已经被占用,等待sem被释放;如果sem=0,信号量空闲,可以执行下面操作 */
    bne   t1, zero, WaitForSem
    /* t1=1 */
    li    t1, 1
    /* 判断链接位;如果是原子操作,把1保存到sem, t1=1,清链接位; 如果不是原子操作,不改变sem的值,t1=0 */
    sc    t1, 0(t0)
    /* 如果t1 = 1,ll sc指令执行成功,获取到信号量; 如果t1=0,获取信号量失败,重新尝试获取 */
    beq   t1, zero, TryAgain
    /* 延迟槽 */
    nop
    /* wait函数返回,ll sc执行成功,进入临界区,执行原子操作 */
    jr    ra

ll sc指令执行失败的情况:
1. 在ll sc指令之间发生了异常,eret指令会破坏原子操作,清除不可见的硬件链接位
2. 多处理器系统的另一个cpu改写了那个位置的内存数据,或改写了附近的内存数据(在同一个cacheline)



作者声明:本文是作者学习总结,能力有限,难免出现问题,如发现问题会及时修改。如有侵权,联系本人删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值