GO中sync 包的 RWMutex 读写互斥锁

背景

Mutex 互斥锁是严格锁定读和写,如果我们需要单独对读或者写添加锁需要使用 sync包的RWMutex
针对读多写少的情况:

读写锁的原则是
1、可以随便读,多个协程同时读。
2、写的时候,不能读也不能写。

RWMutex 简介

RWMutex 类型一共有 6 个方法,

RLock/RUnlock:RLock 锁定读操作,如果锁已被写操作持有,RLock 方法会被阻塞,直到锁释放;如果锁已被读操作持有,则无限制,可以读取内容。RUnlock 是读操作对应的释放锁的方法。

Lock/Unlock:Lock 锁定读写操作,不管是读操作持有锁,还是写操作持有锁,Lock 方法都会被阻塞,直到锁释放。Unlock 是对应的释放锁方法。一般用于写操作的场景。

rUnlockSlow:检查读操作是否全部释放锁,如果读锁全部释放,才可以唤醒写操作去请求写锁。

RLocker:RLocker 为读操作返回一个 Locker 接口,它的 Lock 方法会调用 RWMutex 类型的 RLock方法,它的 Unlock 方法会调用 RWMutex 类型的 RUnlock方法。

其中 RLock()RLock() 之间并不互斥,可以共享锁,Lock()Lock() 之间还有 RLock()Lock() 之间是互斥的.

代码验证

多个协程请求读锁 RLock()RLock()


package main

import (
	"fmt"
	"time"
	"sync"
)

// 声明Mutex变量
var mu *sync.RWMutex
var count = 0
func main() {
   mu = new(sync.RWMutex)
   for i:= 0; i< 1000; i++ {
      go readLock(i)
   }
   time.Sleep(2*time.Second)
}

func readLock(i int) {
   mu.RLock()
   count++
   fmt.Println(i," Read Lock is", count)
   mu.RUnlock()
}

在这里插入图片描述

如上代码所示, 我们启动1000个协程,每个协程执行的readLock 中都添加了 RLock(). 执行结果如下:

结果发现,count 数字打印杂乱无章,说明这些协程同时持有锁,多个RLock() 之间并不互斥。

读写交错 RLock()Lock()

写入的时候读取

package main

import (
	"fmt"
	"time"
	"sync"
)

// 声明Mutex变量
var mu *sync.RWMutex
var count = 0
func main() {
   mu = new(sync.RWMutex)
   for i := 0; i< 5; i++ {
      go readLock(1)
   }
   for i := 0; i< 5; i++ {
      go writLock(1)
   }
   time.Sleep(30*time.Second)
}

func writLock(i int){
   mu.Lock()
   fmt.Println(i," Writ Lock start", count)
   count++
   fmt.Println(i," Writ Lock is", count)
   time.Sleep(1 *time.Second)
   fmt.Println(i," Writ Lock done", count)
   mu.Unlock()
}

func readLock(i int) {
   mu.RLock()
   fmt.Println(i," Read Lock is", count)
   // time.Sleep(10 *time.Second)
   fmt.Println(i," Read Lock done")
   mu.RUnlock()
}

Lock() 写入的时候,sleep 期间, 使用 RLock() 读取, 结果如下
在这里插入图片描述
发现在 write 等待的时候 read 并没有获得锁, 说明 Lock() 锁未释放, RLock() 不能获得锁

读取的时候写入

package main

import (
	"fmt"
	"time"
	"sync"
)

// 声明Mutex变量
var mu *sync.RWMutex
var count = 0
func main() {
   mu = new(sync.RWMutex)
   for i := 0; i< 10; i++ {
      go readLock(1)
   }
   for i := 0; i< 10; i++ {
      go writLock(1)
   }
   time.Sleep(15*time.Second)
}

func writLock(i int){
   mu.Lock()
   fmt.Println(i," Writ Lock start", count)
   count++
   fmt.Println(i," Writ Lock is", count)
   // time.Sleep(1 *time.Second)
   fmt.Println(i," Writ Lock done", count)
   mu.Unlock()
}

func readLock(i int) {
   mu.RLock()
   fmt.Println(i," Read Lock is", count)
   time.Sleep(10 *time.Second)
   fmt.Println(i," Read Lock done")
   mu.RUnlock()
}

RLock() sleep 期间, 使用 Lock() 结果如下

在这里插入图片描述
read 期间, writ 并没有获得锁。 证明了 RLock()Lock() 是互斥的。

请求多个写Lock()Lock()


package main

import (
	"fmt"
	"time"
	"sync"
)

// 声明Mutex变量
var mu *sync.RWMutex
var count = 0
func main() {
   mu = new(sync.RWMutex)
   for i:= 0; i< 1000; i++ {
      go writLock(i)
   }
   time.Sleep(2*time.Second)
}

func writLock(i int){
   mu.Lock()
   count++
   fmt.Println(i," Writ Lock is", count)
   mu.Unlock()
}

启动1000个线程, 使用 Lock() 执行 count ++, 结果如下
在这里插入图片描述
发现最红结果是1000,并且是按照顺序进行计算的。 说明多个协程之间的Lock() 是互斥的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值