Golang锁原理如何实现


这篇文章主要介绍了Golang锁原理如何实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Golang锁原理如何实现文章都会有所收获,下面我们一起来看看吧。锁的本质,就是一种资源,是由操作系统维护的一种专门用于同步的资源比如说互斥锁,说白了就是一种互斥的资源。只能有一个进程(线程)占有。当一个进程(线程)通过竞争获得锁的时候,其他进程(或线程)将得不到这把锁。这是内核代码决定的如果我们希望某种资源在多个进程(线程/协程)之间共享,但是某一时刻最多有一个进程占有,这不就是互斥锁的概念吗,也就是说,我们希望自己的资源也变成一种锁最简单的办法就是将自己的资源和操作系统定义好的锁绑定到一起。也就是说,进程要获取我的资源之前,必须要获得操作系统的锁。进一步说,得锁得资源,失锁失资源。这样的话,我们的资源也变成了一把锁并发编程中保证数据一致性和安全性的Golang的提供的同步机制有sync模块下的Mutex、WaitGroup以及语言自身提供的chan等。 这些同步的方法都是以runtime中实现的底层同步机制(cas、atomic、spinlock、sem)为基础的cas(Compare And Swap)和原子运算是其他同步机制的基础原子操作:指那些不能够被打断的操作被称为原子操作,当有一个CPU在访问这块内容addr时,其他CPU就不能访问CAS:比较及交换,其实也属于原子操作,但它是非阻塞的,所以在被操作值被频繁变更的情况下,CAS操作并不那么容易成功,不得不利用for循环以进行多次尝试自旋锁是指当一个线程在获取锁的时候,如果锁已经被其他线程获取,那么该线程将循环等待,然后不断地判断是否能够被成功获取,知直到获取到锁才会退出循环。获取锁的线程一直处于活跃状态
Golang中的自旋锁用来实现其他类型的锁,与互斥锁类似,不同点在于,它不是通过休眠来使进程阻塞,而是在获得锁之前一直处于活跃状态(自旋)实现休眠和唤醒协程的一种方式信号量有两个操作P和V
P(S):分配一个资源
1. 资源数减1:S=S-1
2. 进行以下判断
如果S 如果S>=0,直接返回V(S):释放一个资源
1. 资源数加1:S=S+1
2. 进行如下判断
如果S>0,直接返回
如果S
golang中信号量操作:runtime/sema.go
P操作:runtime_Semacquire
V操作:runtime_Semreleasemutex的使用mutex的必要性锁在高度竞争时会不断挂起恢复线程从而让出cpu资源,原子变量在高度竞争时会一直占用cpu;原子操作时线程级别的,不支持协程state表示当前锁的状态,是一个共用变量state: |32|31|….|3|2|1|
__________/ | |
| | |
| | 当前mutex是否加锁
| |
| 当前mutex是否被唤醒
|免费云主机域名
等待队列的goroutine协程数Lock 方法申请对 mutex 加锁的时候分两种情况无冲突 通过 CAS 操作把当前状态设置为加锁状态有冲突 通过调用 semacquire 函数来让当前 goroutine 进入休眠状态,等待其他协程释放锁的时候唤醒UnLock 解锁分两步解锁,通过CAS操作把当前状态设置为解锁状态唤醒休眠协程,CAS操作把当前状态的waiter数减1,然后唤醒休眠goroutine知识点使用&来判断位值,使用|来设置位值,使用&^来清空位置(内存对齐)一代互斥锁的问题处于休眠中的goroutine优先级低于当前活跃的,unlock解锁的瞬间最新的goroutine会抢到锁
大多数果锁的时间很短,所有的goroutine都要休眠,增加runtime调度开销Lock 方法申请对 mutex 加锁的时候分三种情况无冲突 通过 CAS 操作把当前状态设置为加锁状态有冲突 开始自旋,并等待锁释放,如果其他 goroutine 在这段时间内释放了该锁,直接获得该锁;如果没有释放,进入3有冲突 通过调用 semacquire 函数来让当前 goroutine 进入等待状态,等待其他协程释放锁的时候唤醒path: runtime/proc.go问题:还是没有解决休眠进程优先级低的问题基本逻辑Mutex 两种工作模式,normal 正常模式,starvation 饥饿模式。normal 情况下锁的逻辑与老版相似,休眠的 goroutine 以 FIFO 链表形式保存在 sudog 中,被唤醒的 goroutine 与新到来活跃的 goroutine 竞解,但是很可能会失败。如果一个 goroutine 等待超过 1ms,那么 Mutex 进入饥饿模式饥饿模式下,解锁后,锁直接交给 waiter FIFO 链表的第一个,新来的活跃 goroutine 不参与竞争,并放到 FIFO 队尾如果当前获得锁的 goroutine 是 FIFO 队尾,或是等待时长小于 1ms,那么退出饥饿模式normal 模式下性能是比较好的,但是 starvation 模式能减小长尾 latencyLOCK流程:无冲突 通过 CAS 操作把当前状态设置为加锁状态有冲突 开始自旋 如果是饥饿模式禁止自旋,开始自旋,并等待锁释放,如果其他 goroutine 在这段时间内释放了该锁,直接获得该锁;如果没有释放,进入3有冲突,且已经过了自旋阶段 通过调用 semacquire 函数来让当前 goroutine 进入等待状态,等待其他协程释放锁的时候唤醒,休眠前:如果是饥饿模式,把当前协程放到队列最前面;唤醒后:如果是饥饿模式唤醒的,直接获得锁UnLock 解锁分两步解锁,通过CAS操作把当前状态设置为解锁状态唤醒休眠协程,CAS操作把当前状态的waiter数减1,然后唤醒休眠goroutine,如果是饥饿模式的话,唤醒等待队列的第一个关于“Golang锁原理如何实现”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“Golang锁原理如何实现”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注百云主机行业资讯频道。

相关推荐: JavaScript如何使用Array.isArray()方法

小编给大家分享一下JavaScript如何使用Array.isArray()方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面免费云主机域名让我们一起去了解一下吧!顾名思义,此方法可用于识别给定参数是否为数…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

Like (0)
Donate 微信扫一扫 微信扫一扫
Previous 05/22 09:12
Next 05/22 09:20

相关推荐