sync mutex golang

互斥锁Mutex实现:

参考代码分析:https://www.jianshu.com/p/ce1553cc5b4f

大致介绍

sema 是一个互斥的信号量,初始默认值是 0,用于将 goroutine park 休眠或是唤醒。sema acquire 时如果 sema 大于 0,那么减一返回,否则休眠等待。sema release 将 sema 加一,然后唤醒等待队列的第一个 goroutine

sema为非零值
Sem acquire Mutex: 大于 0,那么减一返回,否则休眠等待
Sem release: 将sema加一,然后唤醒等待队列的第一个goroutine

state 存贮锁当前的状态

锁开发历程:

粗粒度 -> 添加自旋 -> 添加饥饿状态

添加自旋:解决切换goroutine状态的问题,goroutine都要休眠 park, 徒增 runtime 调度的开销
spin就是cpu空跑,对应汇编代码里面的pause

添加饥饿状态:新加了starving状态,如果当前处于starving状态,新进来的goroutine是获取不到lock的,直接加入
等待队列(先进先出FIFO)
退出饥饿状态的条件:当前 Goroutine 是互斥锁上的最后一个等待的协程或者等待的时间小于 1ms,那么它会将互斥锁切换回正常模式

场景

按照场景去理解代码,更加好理解
场景1:
第一步上锁:只是修改state为1
直接解锁:直接state减1

场景2:
第一步goroutine1上锁,state修改为1

又来一个goroutine2来lock,waiter增加一个
sema默认值为0,semacquire阻塞,(sema-1是否小于0,如果小于0,则挂住)

这时goroutine1解锁,调用semrelease,sema加一,state变为0,waiter减一

goroutine2 semacquire阻塞解开,sema减1
awoke设置为true,重新进入循环,此时state为0,直接break掉,设置状态为new,goroutine2 lock住

场景3:
第一步goroutine1上锁,state修改为1

又来一个goroutine2来lock,waiter增加一个
sema默认值为0,semacquire阻塞

这时goroutine1解锁,调用semrelease,sema加一,state变为0,waiter减一
goroutine2 semacquire阻塞解开,sema减1
awoke设置为true,重新进入循环,此时state为0,sema为0

此时goroutine3进来lock,此state变为1,goroutine3获得锁,返回
goroutine2,重新进入循环,awoke为true,重新进入上面类似的循环

上一篇:[转]Go 互斥锁(sync.Mutex)和 读写锁(sync.RWMutex)


下一篇:Context详解