Go面试看这里了~(五)-Mutex锁相关

161 篇文章 12 订阅

原文地址:Go面试看这里了~(五)

1、mutex的正常模式和饥饿模式?

正常模式(非公平锁):所有等待锁的goroutine按先进先出的顺序等待,唤醒的goroutine不会直接拥有锁,而是回合新请求锁的goroutine竞争锁的拥有权,新请求锁的goroutine有优势(1、正在CPU上执行;2、可能同时拥有好几个锁),所以刚刚唤醒的goroutine很大可能在竞争锁时失败,此时,这个刚唤醒的goroutine会加入到等待队列的前面,如等待的goroutine等待时间超过1ms没获取到锁,此goroutine将会把锁转变为饥饿模式。

饥饿模式(公平锁):是为了解决等待goroutine队列过长问题,此模式下,直接由unlock将锁交给队列中排在第一位的goroutine,同时,新进来的goroutine不会参与抢锁,也不会进入自旋状态,会直接进入队列尾部,如此就解决了老goroutine一直抢不到锁的场景。

饥饿模式的触发条件:

  1. goroutine等待锁时间超过1ms。

  2. 当前队列只剩下一个goroutine。

总结来看的话,正常模式下的性能是最好的,goroutine可连续多次获取锁,饥饿模式解决了取锁公平的问题,但是性能会下降,是性能和公平性的一个平衡模式。

2、mutex允许自旋的条件?

  1. 锁已被占用,且不处于饥饿模式。

  2. 积累的自旋次数小于最大自旋次数(active_spin=4)。

  3. CPU核数大于1。

  4. 有空闲的p。

  5. 当前goroutine所挂载的p下的本地待运行队列为空。

3、RWMutex的实现?

通过积累readerCount读锁数量来进行控制,当有一个写锁时,会将读锁数量设置为-1<<30,目的是让新进入的读锁等待写锁释放之后通知读锁,写锁也会等待之前的读锁释放完毕之后,才会进行后面的操作,写锁释放之后,会将值重新加上1<<30,并通知刚刚新进入的读锁(rw.readerSem),两者互相限制。

4、RWMutex的注意事项?

  1. RWMutex是单写多读锁,该锁可加多个读锁或一个写锁。

  2. 读锁占用情况下会阻止写,不阻止读,多个goroutine可同时获取读锁。

  3. 写锁会阻止其它goroutine(无论读写)进来,整个锁由该goroutine独占。

  4. 适用于读多写少场景。

  5. RWMutex类型变量的零值为未锁定状态的互斥锁。

  6. RWMutex首次被使用后就不能再被拷贝。

  7. RWMutex读锁或写锁在未锁定状态时,解锁会引发panic。

  8. RWMutex一个写锁去锁定临界区的共享资源,如临界区的共享资源已被锁定,进行此操作的goroutine将会被阻塞到解锁。

  9. RWMutex读锁不要用于递归调用,易产生死锁。

  10. RWMutex锁定状态与特定goroutine无关,一goroutine可RLock(Lock),另一goroutine可RUnlock(Unlock)。

  11. 写锁被解锁后,所有因操作锁定读锁而被阻塞的goroutine会被唤醒,并都可成功锁定读锁。

  12. 读锁被解锁后,在未被其它读锁锁定前提下,所有因操作锁定写锁而被阻塞的goroutine,其中等待时间最长的一个goroutine会被唤醒。

5、Cond是什么?

Cond实现一种条件变量,可用在多个reader等待共享资源的ready的场景(如只有一读一写,一个锁或channel就搞定),每个Cond都会关联一个Lock(*sync.Mutex或*sync.RWMutex),当修改条件或调用wait时,必须加锁,保护condition。

6、Broadcast和Signal的区别?

func (c *Cond) Broadcast()func (c *Cond) Signal()

Broadcast会唤醒所有等待C的goroutine,调用Broadcast可加锁,也可不加。

Signal只唤醒一个等待C的goroutin,调用Signal时可加锁,也可不加。

7、Cond中Wait的使用?

func (c *Cond) Wait()c.L.Lock()for !condition() { c.Wait()}... make use of condition ...c.L.Unlock()

wait会自动释放c.L并挂起调用者的goroutine,之后恢复执行,wait会在返回时对c.L加锁,除非被Broadcast或Signal唤醒,否则wait不会返回。

由于wait第一次恢复时,c.L并未加锁,所以当wait返回时,调用者不能假定条件为真,取而代之的是,调用者应在循环中调用wait。

简单来讲,想使用condition,就得加锁。

至此,本次分享就结束了,后期会慢慢补充。

以上仅为个人观点,不一定准确,能帮到各位那是最好的。

好啦,到这里本文就结束了,喜欢的话就来个三连击吧。

扫码关注公众号,获取更多优质内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luyaran

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值