go Mutex (互斥锁)和RWMutex(读写锁)
转载自: https://blog.csdn.net/skh2015java/article/details/60334437
golang中sync包实现了两种锁Mutex (互斥锁)和RWMutex(读写锁),其中RWMutex是基于Mutex实现的,只读锁的实现使用类似引用计数器的功能.
-
type Mutex
- func (m *Mutex) Lock()
- func (m *Mutex) Unlock()
- type RWMutex
- func (rw *RWMutex) Lock()
- func (rw *RWMutex) RLock()
- func (rw *RWMutex) RLocker() Locker
- func (rw *RWMutex) RUnlock()
-
func (rw *RWMutex) Unlock()
其中Mutex为互斥锁,Lock()加锁,Unlock()解锁,使用Lock()加锁后,便不能再次对其进行加锁,直到利用Unlock()解锁对其解锁后,才能再次加锁.适用于读写不确定场景,即读写次数没有明显的区别,并且只允许只有一个读或者写的场景,所以该锁叶叫做全局锁.
func (m *Mutex) Unlock()用于解锁m,如果在使用Unlock()前未加锁,就会引起一个运行错误.
已经锁定的Mutex并不与特定的goroutine相关联,这样可以利用一个goroutine对其加锁,再利用其他goroutine对其解锁.
正常运行例子:
- package main
- import (
- "fmt"
- "sync"
- )
- func main() {
- var l *sync.Mutex
- l = new(sync.Mutex)
- l.Lock()
- defer l.Unlock()
- fmt.Println("1")
- }
- 结果输出:1
当Unlock()在Lock()之前使用时,便会报错
- package main
- import (
- "fmt"
- "sync"
- )
- func main() {
- var l *sync.Mutex
- l = new(sync.Mutex)
- l.Unlock()
- fmt.Println("1")
- l.Lock()
- }
- 运行结果: panic: sync: unlock of unlocked mutex
当在解锁之前再次进行加锁,便会死锁状态
- package main
- import (
- "fmt"
- "sync"
- )
- func main() {
- var l *sync.Mutex
- l = new(sync.Mutex)
- l.Lock()
- fmt.Println("1")
- l.Lock()
- }
- 运行结果: 1
- fatal error: all goroutines are asleep - deadlock!
RWMutex是一个读写锁,该锁可以加多个读锁或者一个写锁,其经常用于读次数远远多于写次数的场景.
func (rw *RWMutex) Lock() 写锁,如果在添加写锁之前已经有其他的读锁和写锁,则lock就会阻塞直到该锁可用,为确保该锁最终可用,已阻塞的 Lock 调用会从获得的锁中排除新的读取器,即写锁权限高于读锁,有写锁时优先进行写锁定
func (rw *RWMutex) Unlock() 写锁解锁,如果没有进行写锁定,则就会引起一个运行时错误.
- package main
- import (
- "fmt"
- "sync"
- )
- func main() {
- var l *sync.RWMutex
- l = new(sync.RWMutex)
- l.Unlock()
- fmt.Println("1")
- l.Lock()
- }
- 运行结果:panic: sync: unlock of unlocked mutex
func (rw *RWMutex) RLock() 读锁,当有写锁时,无法加载读锁,当只有读锁或者没有锁时,可以加载读锁,读锁可以加载多个,所以适用于"读多写少"的场景
func (rw *RWMutex)RUnlock() 读锁解锁,RUnlock 撤销单次 RLock 调用,它对于其它同时存在的读取器则没有效果。若 rw 并没有为读取而锁定,调用 RUnlock 就会引发一个运行时错误(注:这种说法在go1.3版本中是不对的,例如下面这个例子)。
- package main
- import (
- "fmt"
- "sync"
- )
- func main() {
- var l *sync.RWMutex
- l = new(sync.RWMutex)
- l.RUnlock() //1个RUnLock
- fmt.Println("1")
- l.RLock()
- }
- 运行结果:1
- 但是程序中先尝试 解锁读锁,然后才加读锁,但是没有报错,并且能够正常输出.
分析:go1.3版本中出现这种情况的原因分析,通过阅读源码可以很清晰的得到结果
- func (rw *RWMutex) RUnlock() {
- if raceenabled {
- _ = rw.w.state
- raceReleaseMerge(unsafe.Pointer(&rw.writerSem))
- raceDisable()
- }<span style="color:#FF0000;">
- if atomic.AddInt32(&rw.readerCount, -1) < 0 { //readercounter初始值为0,调用RUnLock之后变为-1,继续往下执行
- // A writer is pending.
- if atomic.AddInt32(&rw.readerWait, -1) == 0 { //此时readerwaiter变为1,1-1之后变为0,可以继续以后的操作.</span>
- // The last reader unblocks the writer.
- runtime_Semrelease(&rw.writerSem)
- }
- }
- if raceenabled {
- raceEnable()
- }
- }
当RUnlock多于RLock多个时,便会报错,进入死锁.实例如下:
- package main
- import (
- "fmt"
- "sync"
- )
- type s struct {
- readerCount int32
- }
- func main() {
- l := new(sync.RWMutex)
- l.RUnlock()
- l.RUnlock() //此处出现死锁
- fmt.Println("1")
- l.RLock()
- }
- 运行结果:
- 1
- fatal error: all goroutines are asleep - deadlock!
总结:
所以在go1.3版本中,运行过程中允许RUnLock早于RLock一个,也只能早于1个(注:虽然代码允许,但是强烈不推荐使用),并且在早于之后必须利用RLock进行加锁才可以继续使用.
go Mutex (互斥锁)和RWMutex(读写锁)的更多相关文章
- Linux 自旋锁,互斥量(互斥锁),读写锁
自旋锁(Spin Lock) 自旋锁类似于互斥量,不过自旋锁不是通过休眠阻塞进程,而是在取得锁之前一直处于忙等待的阻塞状态.这个忙等的阻塞状态,也叫做自旋. 自旋锁通常作为底层原语实现其他类型的锁. ...
- C# 多线程编程之锁的使用【互斥锁(lock)和读写锁(ReadWriteLock)】
多线程编程之锁的使用[互斥锁(lock)和读写锁(ReadWriteLock)] http://blog.csdn.net/sqqyq/article/details/18651335 多线程程序写日 ...
- RWLock——一种细粒度的Mutex互斥锁
RWMutex -- 细粒度的读写锁 我们之前有讲过 Mutex 互斥锁.这是在任何时刻下只允许一个 goroutine 执行的串行化的锁.而现在这个 RWMutex 就是在 Mutex 的基础上进行 ...
- golang RWMutex读写锁分析
RWMutex:是基于Mutex实现的读写互斥锁,一个goroutine可以持有多个读锁或者一个写锁,同一时刻只能持有读锁或者写锁 数据结构设计: type RWMutex struct { w Mu ...
- golang mutex互斥锁分析
互斥锁:没有读锁写锁之分,同一时刻,只能有一个gorutine获取一把锁 数据结构设计: type Mutex struct { state int32 // 将一个32位整数拆分为 当前阻塞的gor ...
- Go 标准库 —— sync.Mutex 互斥锁
Mutex 是一个互斥锁,可以创建为其他结构体的字段:零值为解锁状态.Mutex 类型的锁和线程无关,可以由不同的线程加锁和解锁. 方法 func (*Mutex) Lock func (m *Mut ...
- 多线程并发编程之显示锁ReentrantLock和读写锁
在Java5.0之前,只有synchronized(内置锁)和volatile. Java5.0后引入了显示锁ReentrantLock. ReentrantLock概况 ReentrantLock是 ...
- JUC——线程同步锁(ReentrantReadWriteLock读写锁)
读写锁简介 所谓的读写锁值得是两把锁,在进行数据写入的时候有一个把“写锁”,而在进行数据读取的时候有一把“读锁”. 写锁会实现线程安全同步处理操作,而读锁可以被多个对象读取获取. 读写锁:ReadWr ...
- 锁的封装 读写锁、lock
最近由于项目上面建议使用读写锁,而去除常见的lock锁.然后就按照需求封装了下锁.以简化锁的使用.但是开发C#的童鞋都知道lock关键字用起太方便了,但是lock关键字不支持超时处理.很无奈,为了实现 ...
- C# Mutex互斥锁
Mutex 构造函数 (Boolean, String, Boolean) public Mutex ( bool initiallyOwned, string name, out bool crea ...
随机推荐
- eclipse代码恢复(开发程序代码恢复)
如果误操作,让本地代码丢失了不用怕,Eclipse local history可以恢复. 误删除文件后,直接ctrl+z可以恢复. 拉去代码覆盖了本地,也可以一个一个或者整体进行恢复:http://b ...
- pyinstaller使用-python项目转换成exe可执行文件
http://blog.csdn.net/pipisorry/article/details/50620122 Python不是每个人的计算机里面都有安装,当您写了一个好用的工具,需要一个standa ...
- 连接器与容器的桥梁——CoyoteAdapter
如果把整个tomcat内核最高抽象程度模块化,可以看成是由连接器Connector和容器Container组成,连接器负责HTTP请求接收及响应,生成请求对象及响应对象并交由容器处理,而容器则根据请求 ...
- Android自定义Button的“款式”
要想让你的button呈现出一种不一样的外观,一般会采取以下两种形式 采用selector里面加图片的方式 采用selector用shape进行代码控制的方式 对第一种方式而言,只需要注意好" ...
- 【一天一道LeetCode】#79. Word Search
一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...
- [WinForm]C# .net防止一个程序(WinForm)重复运行的方法。
最近比较忙,邮件预警系统暂停了没时间去处理,临时处理:直接执行exe文件! 可是问题来了: 我点击了两次,原来几乎在同时执行这个进程,我在程序中有线程时间睡眠2秒一次等待队列,打开进程果然两个MAIL ...
- Android官方技术文档翻译——Gradle 插件用户指南(6)
没想到翻译这篇<Gradle 插件用户指南>拖了差不多一个月,还跨年了.不过还好,在2号时终于一口气把剩下的给翻译完了(其实那天剩下的也就不到一章). 今天先发一下第六章,明天再发第七章. ...
- Linux System Programming -- Appendix
这本书附录的名字是 "GCC对C语言的扩展" ,一下的内容是对扩展的总结 类型发现 GCC 允许通过变量的引用识别类型.这种操作支持泛型编程.在 C++.Ada 和 Java™ 语 ...
- 高通android开发摘要
一部分是开源的,可以从codeaurora.org上下载,还有一部分是高通产权的,需要从高通的网站上下载. 将高通产权的代码放到:vendor/qcom/proprietary 1. 设置bms一些参 ...
- NDK 与 JNI 的关系
简介 JNI是java语言提供的Java和C/C++相互沟通的机制,Java可以通过JNI调用本地的C/C++代码,本地的C/C++的代码也可以调用java代码.JNI 是本地编程接口,Java和C/ ...