golang sync.RWMutex总结笔记
背景
最近项目中遇到两次RWMutex死锁问题,所以稍微看了一下资料和源码,稍作记录
源码
type RWMutex struct {
w Mutex // held if there are pending writers
writerSem uint32 // semaphore for writers to wait for completing readers
readerSem uint32 // semaphore for readers to wait for completing writers
readerCount int32 // number of pending readers
readerWait int32 // number of departing readers
}
RWMutex源码分析方面参考资料《go中的sync.RWMutex源码解读》写的比较详细和清晰易懂。
总结
go中锁都是不可重入的,所以同一个协程中获取两次RWmutex锁都可能出现死锁
1. 同一协程获取两次RLock
此场景参考前一篇文章《golang RWMutex RLock重入导致死锁》,同一协程两次获取RLock,如果在第二次获取RLock之前,有其他协程获取写锁Lock则会导致死锁。
这种场景和同一协程先获取Lock再获取RLock是一样的原理,由于协程1获取了RLock,导致协程2获取Lock时会被阻塞,然而协程2获取Lock时会将rw.readerCount置为<0的负值,然后协程1再获取RLock也会被阻塞,所以导致两个协程相互阻塞了。
2. 同一协程先获取RLock再获取Lock
func TestLockUp(t *testing.T) {
var l sync.RWMutex
l.RLock()
t.Log("acquire read lock")
l.Lock()
t.Log("acquire write lock")
l.Unlock()
l.RUnlock()
}
读锁是会阻塞写锁的;从源代码中可以看到,在获取Lock时,如果已经有协程获取了RLock,则获取Lock的协程会阻塞在获取rw.writerSem信号量上,在读锁RLock解锁时会唤醒该信号量,然后RLock在等待Lock解锁才能执行RUnLock,因此造成死锁。
3. 同一协程先获取Lock再获取RLock
func TestLockDown(t *testing.T) {
var l sync.RWMutex
l.Lock()
t.Log("acquire write lock")
l.RLock()
t.Log("acquire read lock")
l.RUnlock()
l.Unlock()
}
写锁也会阻止读锁;从源代码中可以看到,当一个协程获取写锁Lock时,会将rw.readerCount置为<0的负值,而当获取读锁RLock时,先对rw.readerCount加1,如果加1后的结果为负值,则表示有协程已经获取到写锁或者正在等待获取写锁,因而该获取读锁的协程会阻塞在获取rw.readerSem信号量上;因此同一个协程先后获取Lock和RLock会相互阻塞等待从而造成死锁。
从这里也能看出来,在RWMutex中,写锁的优先级高于读锁,只要有协程在等待获取写锁,后续的读锁都需要等待。
4. 同一协程获取两次Lock
func TestReLock(t *testing.T) {
var l sync.RWMutex
l.Lock()
t.Log("acquire write lock")
l.Lock()
t.Log("acquire write lock")
l.Unlock()
l.Unlock()
}
写锁阻止写锁;同样,第二个Lock会阻塞在获取rw.writeSem信号量上,导致两个Lock都无法执行Unlock。
总之一句话,go中RWLock不支持可重入,不要在同一协程调用多次RWMutex的锁,不管读锁还是写锁。
5. 写锁优先级高于读锁
有写锁等待时,优先加写锁,因此写锁不至于饿死一直无法获取到锁。
写操作到来时,会把RWMutex.readerCount值拷贝到RWMutex.readerWait中,用于标记排在写操作前面的读者个数。
前面的读操作结束后,除了会递减RWMutex.readerCount,还会递减RWMutex.readerWait值,当RWMutex.readerWait值变为0时唤醒写操作。
参考资料
go中的sync.RWMutex源码解读
Go 并发实战 -- sync RWMutex
golang sync.RWMutex总结笔记的更多相关文章
- golang sync.RWMutex
sync.RWMutex package main import ( "fmt" "runtime" "sync" ) func click ...
- golang中sync.RWMutex和sync.Mutex区别
golang中sync包实现了两种锁Mutex (互斥锁)和RWMutex(读写锁),其中RWMutex是基于Mutex实现的,只读锁的实现使用类似引用计数器的功能. type Mutex f ...
- golang实现分布式缓存笔记(一)基于http的缓存服务
目录 前言 cache 缓存服务接口 cache包实现 golang http包使用介绍 hello.go Redirect.go http-cache-server 实现 cacheHandler ...
- golang sync包
sync 在golang 文档上,golang不希望通过共享内存来进行进程间的协同操作,而是通过channel的方式来进行,当然,golang也提供了共享内存,锁等机制进行协同操作的包: 互斥锁: M ...
- golang sync.Cond条件变量的使用
cond.Wait()的操作实际上是对与cond绑定的锁先进行解锁,在等待通知:接收到通知后,会尝试加锁,加锁成功则唤醒否则继续等待通知: cond.Waite()前必须对关连锁加锁,否则panic ...
- Golang sync
Go1.9.2 sync库里包含下面几类:Mutex/RWMutex/Cond/WaitGroup/Once/Map/Pool 1.Mutex:互斥锁,等同于linux下的pthread_mutex_ ...
- Go 互斥锁(sync.Mutex)和 读写锁(sync.RWMutex)
什么时候需要用到锁? 当程序中就一个线程的时候,是不需要加锁的,但是通常实际的代码不会只是单线程,所以这个时候就需要用到锁了,那么关于锁的使用场景主要涉及到哪些呢? 多个线程在读相同的数据时 多个线程 ...
- Go语言协程并发---读写锁sync.RWMutex
package main import ( "fmt" "sync" "time" ) /* 读写锁 多路只读 一路只写 读写互斥 */ / ...
- Golang Sync.WaitGroup 使用及原理
Golang Sync.WaitGroup 使用及原理 使用 func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.A ...
- go源码阅读 - sync/rwmutex
相比于Mutex来说,RWMutex锁的粒度更细,使用RWMutex可以并发读,但是不能并发读写,或者写写. 1. sync.RWMutex的结构 type RWMutex struct { // 互 ...
随机推荐
- WSL2 网络异常排查 [ping 不通、网络地址异常、缺少默认路由、被宿主机防火墙拦截]
最近在使用的 wsl2 的时候突然发现 wsl2 无法正常联网,即 ping 不通外网以及宿主机的 wsl 网卡.但是将 wsl 版本设置为 1 就可以联网了. 如果你是正常使用的时候,并且自己没有手 ...
- anaconda在sys.path删除~/.local/lib
python -m site python -m site -help USER_SITE='~/anaconda3/envs/test/lib/python3.7/site-packages'
- iOS SDK开发
一款好用且设计充分的 SDK 必须要遵循以下 4 条基本原则,即: 1.SDK 安全,稳定2.统一的开发规范3.Library 小而精4.不依赖第三方 SDK安全,稳定:考虑到 SDK 是需要嵌入到 ...
- What is REST and Restful?
什么是rest 和 restful? 提出rest的作者,目的:符合框架原理的情况下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强,性能好,适宜通讯的架构. Fielding将他对互联网 ...
- HTML图片上传实时预览js
<style>*{margin:0; padding:0;}form{background:#F1F1F1;}.bbg{background:url(../images/add_ico.j ...
- 集群笔记-fence
fence机制: 隔离主机到存储的连接 配置fence_xvm步骤 KVM fence 请问物理机器需要真实的fence 设备吗? 否 一.将物理机器(宿主机)f0配置成fence设备 1. 安装fe ...
- Django+VUE.js实现图片上传
vue里的代码 <template> <div> 添加商品<input v-model="name"><br> 价格<inpu ...
- k8s master高可用
每台master都要部署haproxy,keepalived keepalived 配置文件:! Configuration File for keepalivedglobal_defs { rout ...
- 暑假学习四 8.26 Hadoop的简单使用
先说今日情况,本来打算返校结果回不去,然后身体差发烧了,就随便学了一些东西,阑尾炎还是好疼. 有一说一,我觉得我的电脑真的有点拉啊,三台虚拟机开启之后,运存直接90%,呜呜响,和我本人情况一样,麻了 ...
- Docker学习——Dockerfile 指令详解(五)
我们已经介绍了 FROM (指定基础镜像) , RUN(执行命令) ,还提及了 COPY , ADD ,其实 Dockerfile 功能很强大,它提供了十多个指令.下面我们继续讲解其他的指令. COP ...