Mutex
Mutex结构体
type Mutex struct {
state int32 //表示互斥锁的状态,比如是否被锁定等
sema uint32 //表示信号里,协程阻塞等待的信号量,解锁的协程释放信号量从而唤醒等待信号量的协程
}
- Locked: 表示Mutex是否已被锁定(1表示已经被锁定)
- Woken: 表示是否有协程被唤醒(1已有协程唤醒,正在加锁过程中)
- Starving: 表示Mutex是否处于饥饿状态(1表示饥饿状态,说明有协程阻塞超过1ms)
- Waiter: 表示阻塞等待锁的协程个数,协程解锁时根据此值来判断是否需要释放洗好了.
协程之间抢锁实际上是抢给Locked赋值的权利,能给Locked值置为1,就说明抢锁成功.抢不到的话就阻塞等待Mutex.sema信号量,一旦持有锁的协程解锁,等到的协程就会被依次唤醒.
Mutex只有两个方法:
- Lock()加锁
- Unlock()解锁
加锁被阻塞以及解锁唤醒协程
自旋(CPU的"PAUSE"指令,CPU空转,什么也不做)
加锁时,如果当前Locked为1,说明该锁由其他协程持有,尝试加锁的协程并不是马上转入阻塞,而是会持续的探测Locked位是否变为0,这个过程即为自旋过程.自旋时间很短,但如果自旋过程中发现锁已经被释放,那么协程可以立即获取锁.(可以避免协程间的切片)
Mutex模式
normal模式
默认情况下,Mutex的模式位normal,该模式下,协程如果加锁不成功不会立即转入阻塞排队,而是判断是否满足自旋条件,如果满足则会启动自旋过程,抢锁.
starvation模式
自旋过程中能抢到锁的话,说明此时一定有协程释放了锁,释放锁时如果发现有阻塞等待的协程,还会释放一个信号量来唤醒一个等待协程,被唤醒的协程获得CPU开始运行,此时发现锁被抢占,自己再次阻塞,但是如果阻塞时间已经超过1ms,starving将被标记为1(饥饿模式)
饥饿模式下,不会启动自旋过程.
Woken状态
Woken状态用于加锁和解锁过程的通信.
读写锁
type RWMutex struct {
w Mutex //用于控制多个写锁,获得写锁首先要获取该锁,如果有一个写锁在进行,那么再到来的写锁将会阻塞于此
writerSem uint32 //写阻塞等待的信号量,最后一个读者释放锁时会释放信号量
readerSem uint32 //读阻塞的协程等待的信号量,持有写锁的协程释放锁后会释放信号量
readerCount int32 //记录读者个数
readerWait int32 //记录写阻塞时读者个数
}
接口定义
- RLock(): 读锁定,等待写操作结束(如果有)
- RUnlock(): 解除读锁定,唤醒等待写操作的协程(如果有)
- Lock(): 写锁定,与Mutex完全一致,阻塞等待所有读操作结束(如果有)
- Unlock(): 解除写锁定,与Mutex一致,唤醒因读锁定而被阻塞的协程(如果有)