互斥锁本质是当一个协程访问的时候,其他协程都不能访问.
其实主要是想:修改数据要同步,这样其他协程才可以感知到,所以真正的互斥应该是读取和修改,修改和修改之间,读和读是没有互斥操作的必要的
读写锁可以让多个读并发,但是对于写是互斥的.
当一个协程在写的时候,其他协程不能读也不能写
同时只能存在写锁定或读锁定(读和写互斥)
sync.RWMutex
func (*RWMutex) Lock()
func (*RWMutex) UnLock()
另一组表示对读操作的锁定和解锁,简称为读锁定和读解锁
func (*RWMutex) RLock()
func (*RWMutex) RUlock()
读时共享,写时独占.
写优先级比读高
读锁也算个锁,锁只能有一把
package main
import (
"fmt"
"sync"
)
func main() {
var mutex sync.Mutex
fmt.Printf("%+v\n", mutex)
mutex.Lock()
fmt.Printf("%+v\n", mutex)
mutex.Unlock()
fmt.Printf("%+v\n", mutex)
}
输出
{state:0 sema:0}
{state:1 sema:0}
{state:0 sema:0}
可以看出当Lock()时,state为1,Unlock()时,state为0。
使用读写锁,最好不要和channel一起使用会造成死锁
//创建读写锁
var mx sync.RWMutex
//读
func readGo(in <-chan int, idx int) {
for {
//mx.RLock() //读锁
//要求写端同时在线,自己阻塞
num := <-in
fmt.Println("读取: ", num, idx)
time.Sleep(time.Millisecond * 300) //放大实验现象
//mx.RUnlock()
}
}
//写
func writeGo(out chan<- int, idx int) {
for {
//生成随机数
num := rand.Intn(1000)
mx.Lock() //写锁
out <- num
fmt.Println("------写入: ", num, idx)
time.Sleep(time.Millisecond * 30) //放大实验现象
mx.Unlock()
}
}
func main() {
//播种随机数
rand.Seed(time.Now().UnixNano())
ch := make(chan int) //数据传递的channel
for i := 0; i < 5; i++ {
go writeGo(ch, i+1)
}
for i := 0; i < 5; i++ {
go readGo(ch, i+1)
}
for {
;
}
}
全局变量数据同步
//创建读写锁
var mx sync.RWMutex
var i int //全局变量模拟共享数据
//读
func readGo(idx int) {
for {
mx.RLock() //读锁
num := i
fmt.Println("读取: ", num, idx)
//time.Sleep(time.Millisecond * 30) //放大实验现象
mx.RUnlock()
}
}
//写
func writeGo(idx int) {
for {
mx.Lock() //写锁
//生成随机数
num := rand.Intn(1000)
i = num
fmt.Println("------写入: ", num, idx)
time.Sleep(time.Millisecond * 30) //放大实验现象
mx.Unlock()
}
}
func main() {
//播种随机数
rand.Seed(time.Now().UnixNano())
for i := 0; i < 5; i++ { //5个读过程
go readGo(i+1)
}
for i := 0; i < 5; i++ { //5个写过程
go writeGo(i+1)
}
for {
;
}
}