简介

互斥锁本质是当一个协程访问的时候,其他协程都不能访问.
其实主要是想:修改数据要同步,这样其他协程才可以感知到,所以真正的互斥应该是读取和修改,修改和修改之间,读和读是没有互斥操作的必要的

读写锁可以让多个读并发,但是对于写是互斥的.
当一个协程在写的时候,其他协程不能读也不能写
同时只能存在写锁定或读锁定(读和写互斥)

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 {
      ;
   }
}