互斥锁的实现原理

mutex的本质就是一个内存标志,这个标志可以是一个flag(占用标志),也可以是一个指针,指向一个持有者的线程ID,也可以是两个都有,以及一个等待(阻塞)队列,以及若干其它信息等。。当这个flag被标记成被占用的时候,或者持有者指针不为空的时候,那么它就不能被被别的任务(线程)访问。只有等到这个mutex变得空闲的时候,操作系统会把等待队列里的第一任务(线程)取出来,然后调度执行,如果当前CPU很忙,那么就把取出的这个任务(线程)标记为就绪(READY)状态,后续如果CPU空闲了,就会被调度。一般来说,面试回答到这个程度,我觉得就够了。

如果面试官继续问:占用标志怎么实现的,那么继续解释:

这个占用标志flag,利用硬件的原子操作来实现,比如x86汇编里有CMPXCHG指令,就可以实现比较+原子交换,锁都是用这个实现的。单核CPU就是用这个实现的。操作mutex之前,还会关中断,保证这个操作的唯一性。解释到这一步,已经很底层了,如果面试的是一般的驱动、底层开发岗位,这个解释应该也够用了,因为单核CPU就是这么做的。

如果面试官继续问:多核怎么实现的,那么继续解释:

多核的同步就非常复杂了,多核的锁的实现,都会涉及到另外一个概念,就是spinlock(自旋锁),spinlock能实现多核的锁定,spinlock锁定多核以后,再操作锁的占用标志就是被保护的状态,操作完以后还要用memory barriar(内存屏障)保证锁的状态可以同步到所有的核心。说实话,解释到spinlock,已经应该算是对操作系统很了解了。

如果面试官继续问:spinlock怎么实现的,那么继续解释(你要面试什么岗位,连spinlock都要做?):

spinlock的本质是一个广播,实现的方式就很多:效率低下的方法之一是使用核间中断(IPI),通知其它核心说,我要持有spinlock,你们都要等我,但这种同步方法比较麻烦,我印象里好像已经没有操作系统这么做了。现代操作系统应该用的都是标志位法,具体的实现方法是:

#1,先给每个核准备一个spinlock的状态标志;
#2,当有代码要持有spinlock的时候,先关闭当前核心的中断;
#3,通过原子操作把当前核心的spinlock标志置为已经持有的状态;
#4,如果持有当前核心的spinlock失败,那么进入忙等的状态,直到持有当前核心的spinlock状态为止;
#5,继续尝试持有其它核心的spinlock状态,如果发现其它核心的spinlock是占用的状态,那么不同操作系统的设计思路可能就是不一样了:
#5.1,有的操作系统采用的是回退法,所有核心都放弃自己的spinlock状态,然后随机延迟几个tick,再重新尝试持有;
#5.2,有的操作系统采用的是不同核心不同优先级的做法,按照CPU核心的编号去排序分配优先级;
#5.3,有的操作系统会根据持有的spinlock的核心数量做比较,数量多的优先级更高,如果两个spinlock持有的核心一样多,那么随机选一个;
#6,经过#5的抢占操作,终于有一个核心的spinlock函数拿到了所有的核心的spinlock状态,此时其它核心都会进入等待的状态,总之,是不能继续跑了,至少不能继续抢占某个内存区域了。然后持有spinlock的核心就可以放心的修改mutex的占用状态,广播到所有核心,完成锁的状态的更新。

除非是自己写操作系统,否则上面的知识可能用处不大,不过有兴趣的去了解一下也么什么坏处,看Linux源码就能看明白。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值