说明:本文虽然以spinlock函数为例,但并不会深度解读spinlock函数。本文重点解读exclusive机制。
每一个core都有一个Internal exclusive monitor,它有open和exclusive两个状态,管理着:Load-Exclusive accesses 、Store-Exclusive accesses、Clear-Exclusive(CLREX) instructions
Load-Exclusive instruction和Store-Exclusive instruction是LDX, LDAX, STX, STLX
可以使用这些指令去构造semaphores、spinlock,以确保在同一个core之间的不同线程的同步操作。在不同的core之间也是可以使用同一个的coherent memory locations来确保同步。
Load-Exclusive instruction标记一个block用于独占访问的内存, CTR_EL0定义了这个block的大小。
LDXR Wt, [base{,#0}]
(1)、从 base
地址处读取一个数字,存放到Wt寄存器中; (2)、将Monitor的状态变成exclusive
STXR Ws, Wt, [base{,#0}]
(1)、将Wt中的数据写入到 base
地址处,如果成功Ws返回0,否则返回1; (2)、将Monitor从exclusive状态切换成open, 如果切换成功,则说明写入成功,Ws返回0; 如果切换失败,则数据不会写入到内存,Ws返回1
剖析:如果想用独占指令去store一个数,那么必需先要ldx/ldax指令,让Monitor置为exclusive状态,此时它才能继续进行store操作,store完成之后,Monitor将会从exclusive切回open状态。继续白话剖析:我想独占方式往一个地址写数,那么我必需独占monitor,然后我才能往相关地址写数据。
如下一个spinlock的实现,在同一个核上,当有两个线程都要执行这一段代码时。
1、thread1先调用 cpu_spin_lock [&lock1]执行到ldaxr时,此时Internal Exclusive Monitor将标记为exclusive状态。换句话说,core已经是 Exclusive Access state,马上就要准备写操作了。
2、接着thread2也调用 cpu_spin_lock [&lock2]执行了到ldaxr,此时Internal Exclusive Monitor已经是exclusive状态了,无需重新设置。换句话说,core依然是 Exclusive Access state,马上就要准备写操作了。
3、接着thread1先调用了stxr操作,窝槽牛逼啊,直接就成功了,成功将w2写入到[X0]地址处,w1并返回0表示操作成功。此时Internal Exclusive Monitor将会从exclusive切换成open状态。。 4、接着thread2也调用了stxr操作,因为此时Internal Exclusive Monitor已经是open状态了,所以此时的写入操作将会失败。即w2不会被写入到[X0],且w1返回1,反馈给程序一个结果,告诉他:嗨,这步执行没有通过哦。
5、按照上述程序的逻辑,thread2在执行stxr失败后,w1返回1, 此时将程序跳回 l2
处,重新来一遍...
依然是上述的例子,如果是不同的CPU在获取同一把锁会怎样呢?
1、thread1先调用 cpu_spin_lock [&lock1]执行到ldaxr时,此时core1的Internal Exclusive Monitor将标记为exclusive状态。换句话说,core1已经是 Exclusive Access state,马上就要准备写操作了。
2、接着thread2也调用 cpu_spin_lock [&lock2]执行了到ldaxr,此时core2的Internal Exclusive Monitor将标记exclusive状态,换句话说,core依然是 Exclusive Access state,马上就要准备写操作了。
3、接着thread1先调用了stxr操作,窝槽牛逼啊,直接就成功了,成功将w2写入到[X0]地址处,w1并返回0表示操作成功。此时Internal Exclusive Monitor将会从exclusive切换成open状态。。
4、接着thread2也调用了stxr操作,因为此时core2的Internal Exclusive Monitor依然经是exclusive状态了,所以此时的写入操作会成功。
依然是上述的例子,如果是不同的CPU在获取同一把锁会怎样呢?
1、thread1先调用 cpu_spin_lock [&lock1]执行到ldaxr时,此时core1的Internal Exclusive Monitor将标记为exclusive状态。换句话说,core1已经是 Exclusive Access state,马上就要准备写操作了。
2、接着thread2也调用 cpu_spin_lock [&lock1]执行了到ldaxr,此时core2的Internal Exclusive Monitor将标记exclusive状态,由于[X0]标记exclusive访问,将会被缓存到Coherent memory中,此memory遵循MESI协议,故此时该地址数据也会被同步到Global Monitor的cache和Core2的Internal Monior的cache中,也就是说,此时Global Exclusive Monitor也换成了该地址数据,并且也是exclusive状态了。
3、接着thread1先调用了stxr操作,窝槽牛逼啊,直接就成功了,成功将w2写入到[X0]地址处,w1并返回0表示操作成功。此时core1的Internal Exclusive Monitor将会从exclusive切换成open状态。Global Monitor也会从exclusive切换成open状态
4、接着thread2也调用了stxr操作,根据MESI协议,core2在执行store操作时,必先去snoop core1的cache,此时该地址数据将同步到Global Monitor的cache和core2的Internal Monitore的cache中,此时Global exclusive Monitor将会被置为open状态。因为Global exclusive Monitor缓存了该地址数据,并且为open状态,故stxr操作将失败;
5、如果此时core2再次执行一次ldaxr,然后再去执行stxr则能成功。
6、按照上述程序的逻辑,core2在执行stxr失败后,w1返回1, 此时将程序跳回 l2
处,重新来一遍...
原作者:baron
更多回帖