state表示mutex的状态
上图是Mutex的结构体和locker接口方法定义
Mutex的公平性,两种操作模式 正常normal和饥饿starvation
-
互斥量可分为两种操作模式:正常和饥饿。
-
-
在正常模式下,等待的goroutines按照FIFO(先进先出)顺序排队,但是goroutine被唤醒之后并不能立即得到mutex锁,它需要与新到达的goroutine争夺mutex锁。
-
-
因为新到达的goroutine已经在CPU上运行了,所以被唤醒的goroutine很大概率是争夺mutex锁是失败的。出现这样的情况时候,被唤醒的goroutine需要排队在队列的前面。
-
-
如果被唤醒的goroutine有超过1ms没有获取到mutex锁,那么它就会变为饥饿模式。
-
-
在饥饿模式中,mutex锁直接从解锁的goroutine交给队列前面的goroutine。新达到的goroutine也不会去争夺mutex锁(即使没有锁,也不能去自旋),而是到等待队列尾部排队。
-
-
在饥饿模式下,有一个goroutine获取到mutex锁了,如果它满足下条件中的任意一个,mutex将会切换回去正常模式:
-
-
1. 是等待队列中的最后一个goroutine
-
-
2. 它的等待时间不超过1ms。
-
-
正常模式有更好的性能,因为goroutine可以连续多次获得mutex锁;
-
-
饥饿模式对于预防队列尾部goroutine一致无法获取mutex锁的问题。
下面看下核心方法lock
1.如果当前state为0,代表这个锁没有被持有,所以就通过CAS来获取锁,这个也是快速获取锁的路径
2.如果当前state不为0,那么就进行lockSlow流程
3.判断,如果是饥饿starvation模式,就不自旋,新到达的goroutine必须排队;如果是normal正常模式,就进入自旋,尝试获取锁
4.goroutine已经从sleep中唤醒,所以我们需要重置flag
6.获取锁成功,就直接break,如果之前已经等待过,就在queue的开头排队
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
下面再来看unlock释放锁
1.如果没有lock,直接就unlock,那么就会出现一个run-time 错误
2.一个锁住的mutex,不会专属于一个指定的goroutine;通常是一个goroutine锁住mutex,另一个goroutine争抢,来解锁unlock
3.快速解锁,就是state - mutexLocked,如果不为0,就调用unlockSlow解锁
4.如果没有waiters,或者1个goroutine已经被唤醒,并且抢到了锁,就没有必要唤醒其余的goroutine了
5.如果是饥饿模式,那么就直接解锁下一个waiter,新来的goroutine是需要在队尾排队的,就无法获取
转载:https://blog.csdn.net/kuaipao19950507/article/details/117228721