ARMv8之exclusive操作(一)exclusive操作的引入

AMRv8架构中对于A64,提供了如下的一些exclusive指令,用来支持exclusive操作。


那为什么,arm在加入exclusive指令呢?加入这个,主要是为了解决多核情况下,锁的竞争问题。

在软件层面,对于共享资源的访问,会设定一个锁,只有能拿到这个锁的程序,才能够访问共享资源,而没有拿到锁的程序,就不能访问该共享资源。

拿到锁的程序,在访问完毕后,要释放锁,这样,其他的程序,才可以竞争该锁,从而访问共享资源。

其伪代码如下:

//获取锁
get_lock:
    ldr  w1, [x0]
    cmp  w1, #1
    b.ne get_lock
    //上锁
    mov  w1, #1
    str  w1, [x0]
    //开始访问共享资源
    ...  
    //结束访问共享资源
unlock:
    mov  w1, #0
    str  w1, [x0]

读取锁,如果为非0,表示当前锁被其他程序占有,因此获取锁失败,就一直要等别人释放锁。如果锁的值为0,表示锁没有被其他程序占有,那么将锁置为1,然后访问共享资源。访问完毕后,将锁置为0,释放锁。

这个获取锁的程序,在单核的时候,可以运行得比较良好,因为在同一个时刻,只能有一个程序在执行,不存在竞争的问题。

在使用操作系统后,这个程序也可能会出现潜在的问题,因为操作系统会调度应用程序。假设应用程序A在读取到锁状态后,值为0,表示当前锁没有被其他程序占有,正当自己要将锁锁上的时候,操作系统进行了调度,应用程序B执行。程序B也读取锁状态,发现值为0,表示当前锁没有被其他程序占有,然后将锁给锁上,访问共享资源。此时,操作系统又进行了调度,应用程序A执行,将锁给锁上,然后访问共享资源。那此时,就出现了2个应用程序,同时访问共享资源,锁的作用,被屏蔽了。

其执行过程,如下表所示:

程序A

当前执行

程序B

ldr w1,[x0]

获取锁状态为0

程序A

 
 

程序B

ldr w1,[x0]

获取锁状态为0

 

程序B

str w1, [x0]

上锁,锁状态为1

 

程序B

访问共享资源

b.ne get_lock

此时锁状态为1,但是A不知道

程序A

 

str w1, [x0]

上锁

程序A

 

访问共享资源

程序A

 

为了解决这个问题,可以在获取锁的时候,屏蔽中断,那这个时候,操作系统就不能调度,也就避免上面出现的问题。伪代码如下所示:

get_lock:
    //关中断
    bl     mask_int
    ldr  w1, [x0]
    cmp  w1, #1
    b.ne get_lock
    //上锁
    mov  w1, #1
    str  w1, [x0]
    //开中断
    bl     open_int
    //访问共享资源
    ...  
unlock:
    mov  w1, #0
    str  w1, [x0]

这样,可以避免上述的问题,但是只要获取锁,就要关中断,开中断,这影响了系统响应中断的实时性。

在单核的时候,还可以通过关闭中断,来阻止操作系统调度。但是在多核的情况下,各个cpu是并行执行的,因此这个时候,就会出现,上面描述的2个程序,同时获取到锁的状态,而这个时候,通过禁止中断,是没有效果的。

为了解决多核情况下的锁竞争问题,arm引入了exclusive操作,并添加了相应的指令。

exclusive的操作的核心,就是会将锁,用一个状态机进行维护,该状态机有2种状态,open状态和exclusive状态。要想成功的对锁进行上锁,状态必须要从exclusive状态切换到open状态,其他状态,都是失败的。

为了支持exclusive操作,在A64,新增了LDXR和STXR指令。


在A32和T32下,也加入LDREX和STREX指令来支持。


LDXR指令,将状态从open状态切换到exclusive状态,STXR指令,将状态从exclusive状态切换到open状态,这个就表示store exclusive操作成功。


STXR指令和普通的STR指令,不同的是,该指令有返回值,表示store exclusive是否成功。如果成功,ws为0,不成功,ws为1。

当有了exclusive操作指令后,之前的获取锁的程序,就变为以下:

//获取锁
get_lock:
    ldxr  w1, [x0]
    cmp  w1, #1
    b.ne get_lock
    
    //尝试上锁
    mov  w1, #1
    stxr w2, w1, [x0]
    cbnz w2, get_lock
    //访问资源
    ...   
unlock:
    mov  w1, #0
    str  w1, [x0]

通过stxr指令,尝试更改锁的状态,如果更改成功,那么w2为0,此时就表示自己获取到锁,然后就可以访问共享资源。如果更改失败,那么w2为1,表示此时其他程序获取到该锁,就不能访问共享资源,回到获取锁。

此条目发表在ARM分类目录,贴了标签。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。