原文地址:Go面试看这里了~(五)
1、mutex的正常模式和饥饿模式?
正常模式(非公平锁):所有等待锁的goroutine按先进先出的顺序等待,唤醒的goroutine不会直接拥有锁,而是回合新请求锁的goroutine竞争锁的拥有权,新请求锁的goroutine有优势(1、正在CPU上执行;2、可能同时拥有好几个锁),所以刚刚唤醒的goroutine很大可能在竞争锁时失败,此时,这个刚唤醒的goroutine会加入到等待队列的前面,如等待的goroutine等待时间超过1ms没获取到锁,此goroutine将会把锁转变为饥饿模式。
饥饿模式(公平锁):是为了解决等待goroutine队列过长问题,此模式下,直接由unlock将锁交给队列中排在第一位的goroutine,同时,新进来的goroutine不会参与抢锁,也不会进入自旋状态,会直接进入队列尾部,如此就解决了老goroutine一直抢不到锁的场景。
饥饿模式的触发条件:
-
goroutine等待锁时间超过1ms。
-
当前队列只剩下一个goroutine。
总结来看的话,正常模式下的性能是最好的,goroutine可连续多次获取锁,饥饿模式解决了取锁公平的问题,但是性能会下降,是性能和公平性的一个平衡模式。
2、mutex允许自旋的条件?
-
锁已被占用,且不处于饥饿模式。
-
积累的自旋次数小于最大自旋次数(active_spin=4)。
-
CPU核数大于1。
-
有空闲的p。
-
当前goroutine所挂载的p下的本地待运行队列为空。
3、RWMutex的实现?
通过积累readerCount读锁数量来进行控制,当有一个写锁时,会将读锁数量设置为-1<<30,目的是让新进入的读锁等待写锁释放之后通知读锁,写锁也会等待之前的读锁释放完毕之后,才会进行后面的操作,写锁释放之后,会将值重新加上1<<30,并通知刚刚新进入的读锁(rw.readerSem),两者互相限制。
4、RWMutex的注意事项?
-
RWMutex是单写多读锁,该锁可加多个读锁或一个写锁。
-
读锁占用情况下会阻止写,不阻止读,多个goroutine可同时获取读锁。
-
写锁会阻止其它goroutine(无论读写)进来,整个锁由该goroutine独占。
-
适用于读多写少场景。
-
RWMutex类型变量的零值为未锁定状态的互斥锁。
-
RWMutex首次被使用后就不能再被拷贝。
-
RWMutex读锁或写锁在未锁定状态时,解锁会引发panic。
-
RWMutex一个写锁去锁定临界区的共享资源,如临界区的共享资源已被锁定,进行此操作的goroutine将会被阻塞到解锁。
-
RWMutex读锁不要用于递归调用,易产生死锁。
-
RWMutex锁定状态与特定goroutine无关,一goroutine可RLock(Lock),另一goroutine可RUnlock(Unlock)。
-
写锁被解锁后,所有因操作锁定读锁而被阻塞的goroutine会被唤醒,并都可成功锁定读锁。
-
读锁被解锁后,在未被其它读锁锁定前提下,所有因操作锁定写锁而被阻塞的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,就得加锁。
至此,本次分享就结束了,后期会慢慢补充。
以上仅为个人观点,不一定准确,能帮到各位那是最好的。
好啦,到这里本文就结束了,喜欢的话就来个三连击吧。
扫码关注公众号,获取更多优质内容。