宋宝华: 几个人一起抢spinlock,到底谁先抢到?

宋宝华: 几个人一起抢spinlock,到底谁先抢到?_第1张图片

天问

公平在哪里?

几个人一起抢spinlock,到底谁先抢到呢?这是一个问题。

几个人一起去银行柜台,到底谁先被服务到呢?这是一个问题。

闹地不好就要出问题。这个问题就是公平的问题。这个社会,人人都要讲公平,是一个人人平等、人不吃人的社会。经过本人数年研究,得出一个结论:装逼必然被雷劈,除非自己就是雷。所以我要坚持装孙子,50年不变。

宋宝华: 几个人一起抢spinlock,到底谁先抢到?_第2张图片

斗狠

腿短要吃亏

在早期,2.6.24之前的内核,抢spinlock完全靠斗狠。比如有8个CPU核,CPU0已经持有了spin_lock(),在其释放之前,CPU1-CPU7都来抢(前后顺序可能不一样):

宋宝华: 几个人一起抢spinlock,到底谁先抢到?_第3张图片

那么在CPU0释放spinlock的瞬间,CPU1-CPU7究竟哪个先抢到?不知道,谁狠谁抢到。比如某个核的计算能力强,某个核正好cache命中spinlock对应的变量,它就抢地快。

因为,早期的spinlock大概是这个一个逻辑:

在没有持有锁的情况下:

int count=1

持有锁的过程中:

count=count-1;

if(count==0)

   成功拿到了锁;

if(count < 0)

   证明别人拿到了锁,自己还得继续等。

释放锁的过程:

count = 1;

因此,谁先感觉到count-1==0,谁就成功拿到锁。比如8个人去银行汇款,柜台服务完前一个人后,喊了一句“next one”,那么谁会抢到柜台服务呢?

  1. 刘翔、姚明、长腿欧巴、走路特别快的(CPU猛)

  2. 思想没有在打野,全神灌注盯着柜台的(cache命中)

至于,老弱病残幼,那就完全没戏了;柜台叫“next one”的时候,正在发微信的、玩手机的、吟诗作对的、聊骚的,也完全没戏了!!

这显然太特么不公平了!!像我这么喜欢玩手机的人,按照这种排队方法,在银行哪怕第一个去,恐怕一天也排不到我!!!这叫被饥饿(starved )。

宋宝华: 几个人一起抢spinlock,到底谁先抢到?_第4张图片

叫号

我要玩手机

银行的柜台服务没有那么傻逼。任何一个人去到银行,先取一个号,银行每服务完一个人,就报一个新的号,如果机器报的号等于自己持有的票号,则取得柜台服务。这特么太公平了!!我取完号,我就发微信了,你腿再长也没鸟用,你来的晚,你的号大,柜台叫的号小于你的号,你就得继续等。

spinlock显然需要这个一模一样的机制。这就叫Ticket spinlocks。2.6.25之后的spinlock是这样实现的:

宋宝华: 几个人一起抢spinlock,到底谁先抢到?_第5张图片

owner类似于柜台语音报的号,next是取票的号。它的逻辑大概类似于,谁取票先把spinlock的next暂存到本地local_next,然后把spinlock的next+1,所以后来的人取到的票号肯定更大;谁释放锁就把owner加1。如果spinlock释放后,owner正好等于某个CPU本地暂存的local_next,则这个CPU获得spinlock。

spinlock本身将含有owner和next:

typedef struct {

       struct __raw_tickets {

获取spinlock的过程变成

取号+等待叫号等于自己取的号

宋宝华: 几个人一起抢spinlock,到底谁先抢到?_第6张图片

当然,真实的取号过程要通过ldrex、strex这样的指令来实现原子性:

宋宝华: 几个人一起抢spinlock,到底谁先抢到?_第7张图片

上述代码中,wfe()类似你在发呆、玩微信,这个时候,叫号机通过sev()来唤醒你。

哥写的不是Linux,哥写的是寂寞。


更多精彩,尽在"Linux阅码场",扫描下方二维码关注

宋宝华: 几个人一起抢spinlock,到底谁先抢到?_第8张图片

你的随手转发或点个在看是对我们最大的支持!

你可能感兴趣的:(宋宝华: 几个人一起抢spinlock,到底谁先抢到?)