前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Golang 语言中基础同步原语 Mutex 和 RWMutex 的区别

Golang 语言中基础同步原语 Mutex 和 RWMutex 的区别

作者头像
frank.
发布2021-04-30 11:44:09
发布2021-04-30 11:44:09
3.3K00
代码可运行
举报
运行总次数:0
代码可运行

01

介绍

Golang 语言天生支持并发,关于并发编程,Golang 语言还有一句口号:“不要通过共享内存进行通信;而是通过通信共享内存”。

但是,通过“共享内存进行通信”的方式作为并发编程的解决方案在传统的编程语言中更为流行。在 Golang 语言标准库 sync 包中也提供了“通过共享内存进行通信”的并发编程解决方案。

其中,在 sync 包中最重要的同步工具就是 sync.Mutexsync.RWMutex。因为在之前的文章已经介绍过二者的使用,所以本文我们不再赘述。本文主要介绍使用二者的注意事项和二者的区别。

02

Mutex

Mutex 也称为互斥锁,互斥锁就是互相排斥的锁,它可以用作保护临界区的共享资源,保证同一时刻只有一个 goroutine 操作临界区中的共享资源。互斥锁 Mutex 类型有两个方法,LockUnlock

使用互斥锁的注意事项:

  • Mutex 类型变量的零值是一个未锁定状态的互斥锁。
  • Mutex 在首次被使用之后就不能再被拷贝(Mutex 是值类型,拷贝会同时拷贝互斥锁的状态)。
  • Mutex 在未锁定状态(还未锁定或已被解锁),调用 Unlock 方法,将会引发运行时错误。
  • Mutex 的锁定状态与特定 goroutine 没有关联,Mutex 被一个 goroutine 锁定, 可以被另外一个 goroutine 解锁。(不建议使用,必须使用时需要格外小心。)
  • Mutex 的 Lock 方法和 Unlock 方法要成对使用,不要忘记将锁定的互斥锁解锁,一般做法是使用 defer。

互斥锁源码:

代码语言:javascript
代码运行次数:0
运行
复制
type Mutex struct {
 state int32 // 互斥锁的状态
 sema  uint32 // 信号量,用于控制互斥锁的状态
}

03

RWMutex

RWMutex 也称为读写互斥锁,读写互斥锁就是读取/写入互相排斥的锁。它可以由任意数量的读取操作的 goroutine 或单个写入操作的 goroutine 持有。读写互斥锁 RWMutex 类型有五个方法,LockUnlockRlockRUnlockRLocker。其中,RLocker 返回一个 Locker 接口,该接口通过调用 rw.RLockrw.RUnlock 来实现 Lock 和 Unlock 方法。

使用读写互斥锁的注意事项:

  • RWMutex 类型变量的零值是一个未锁定状态的互斥锁。
  • RWMutex 在首次被使用之后就不能再被拷贝。
  • RWMutex 的读锁或写锁在未锁定状态,解锁操作都会引发 panic。
  • RWMutex 的一个写锁 Lock 去锁定临界区的共享资源,如果临界区的共享资源已被(读锁或写锁)锁定,这个写锁操作的 goroutine 将被阻塞直到解锁。
  • RWMutex 的读锁不要用于递归调用,比较容易产生死锁。
  • RWMutex 的锁定状态与特定的 goroutine 没有关联。一个 goroutine 可以 RLock(Lock),另一个 goroutine 可以 RUnlock(Unlock)。
  • 写锁被解锁后,所有因操作锁定读锁而被阻塞的 goroutine 会被唤醒,并都可以成功锁定读锁。
  • 读锁被解锁后,在没有被其他读锁锁定的前提下,所有因操作锁定写锁而被阻塞的 goroutine,其中等待时间最长的一个 goroutine 会被唤醒。

读写互斥锁源码:

代码语言:javascript
代码运行次数:0
运行
复制
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
}

04

Mutex 和 RWMutex 的区别

RWMutex 和 Mutex 的区别是 RWMutex 将对临界区的共享资源的读写操作做了区分,RWMutex 可以针对读写操作做不同级别的锁保护。

RWMutex 读写锁中包含读锁和写锁,它的 LockUnlock 方法用作写锁保护,它的 RLockRUnlock 方法用作读锁保护。

RWMutex 读写锁中的读锁和写锁关系如下:

  • 在写锁处于锁定状态时,操作锁定读锁的 goroutine 会被阻塞。
  • 在写锁处于锁定状态时,操作锁定写锁的 goroutine 会被阻塞。
  • 在读锁处于锁定状态时,操作锁定写锁的 goroutine 会被阻塞。

但是,在读锁处于锁定状态时,操作锁定读锁的 goroutine 不会被阻塞。我们可以理解为读锁保护的临界区的共享资源,多个读操作可以同时执行。

05

总结

本文我们介绍了 Golang 语言中的基本同步原语互斥锁和读写互斥锁使用时的注意事项,然后总结了二者的区别。读写互斥锁可以对临界区的共享资源做更加细粒度的访问控制,在读锁持有锁时,其他操作读锁的 goroutine 不被被阻塞,(也就是说不限制对临界区的共享资源的并发读)所以在读多写少的场景,我们可以使用读写互斥锁替代互斥锁,提升应用程序的性能。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Go语言开发栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档