宋宝华: 几个人一起抢spinlock,到底谁先抢到?
天问
公平在哪里?
几个人一起抢spinlock,到底谁先抢到呢?这是一个问题。
几个人一起去银行柜台,到底谁先被服务到呢?这是一个问题。
闹地不好就要出问题。这个问题就是公平的问题。这个社会,人人都要讲公平,是一个人人平等、人不吃人的社会。经过本人数年研究,得出一个结论:装逼必然被雷劈,除非自己就是雷。所以我要坚持装孙子,50年不变。
斗狠
腿短要吃亏
在早期,2.6.24之前的内核,抢spinlock完全靠斗狠。比如有8个CPU核,CPU0已经持有了spin_lock(),在其释放之前,CPU1-CPU7都来抢(前后顺序可能不一样):
那么在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”,那么谁会抢到柜台服务呢?
刘翔、姚明、长腿欧巴、走路特别快的(CPU猛)
思想没有在打野,全神灌注盯着柜台的(cache命中)
至于,老弱病残幼,那就完全没戏了;柜台叫“next one”的时候,正在发微信的、玩手机的、吟诗作对的、聊骚的,也完全没戏了!!
这显然太特么不公平了!!像我这么喜欢玩手机的人,按照这种排队方法,在银行哪怕第一个去,恐怕一天也排不到我!!!这叫被饥饿(starved )。
叫号
我要玩手机
银行的柜台服务没有那么傻逼。任何一个人去到银行,先取一个号,银行每服务完一个人,就报一个新的号,如果机器报的号等于自己持有的票号,则取得柜台服务。这特么太公平了!!我取完号,我就发微信了,你腿再长也没鸟用,你来的晚,你的号大,柜台叫的号小于你的号,你就得继续等。
spinlock显然需要这个一模一样的机制。这就叫Ticket spinlocks。2.6.25之后的spinlock是这样实现的:
owner类似于柜台语音报的号,next是取票的号。它的逻辑大概类似于,谁取票先把spinlock的next暂存到本地local_next,然后把spinlock的next+1,所以后来的人取到的票号肯定更大;谁释放锁就把owner加1。如果spinlock释放后,owner正好等于某个CPU本地暂存的local_next,则这个CPU获得spinlock。
spinlock本身将含有owner和next:
typedef struct {
union {
unsigned int slock;
struct __raw_tickets {
unsigned short owner;
unsigned short next;
} tickets;
};
} arch_spinlock_t;
获取spinlock的过程变成
取号+等待叫号等于自己取的号:
当然,真实的取号过程要通过ldrex、strex这样的指令来实现原子性:
上述代码中,wfe()类似你在发呆、玩微信,这个时候,叫号机通过sev()来唤醒你。
哥写的不是Linux,哥写的是寂寞。
更多精彩,尽在"Linux阅码场",扫描下方二维码关注
你的随手转发或点个在看是对我们最大的支持!