Go语言互斥锁和读写锁

一、互斥锁

  • Go语言中多个协程操作一个变量时会出现冲突的问题
  • go run -race 可以查看竞争
  • 可以使用sync.Mutex对内容加锁
  • 互斥锁的使用场景
    • 多个goroutine访问同一个函数(代码段)
    • 这个函数操作一个全局变量
    • 为了保证共享变量安全性,值合法性
  • 使用互斥锁模拟售票窗口
package main

import (
   "fmt"
   "sync"
   "time"
   "math/rand"
)

var (
   //票数
   num = 100
   wg  sync.WaitGroup
   //互斥锁
   mu sync.Mutex
)

func sellTicker(i int) {
   defer wg.Done()
   for {
      //加锁,多个goroutine互斥
      mu.Lock()
      if num >= 1 {
         fmt.Println("第", i, "个窗口卖了", num)
         num = num - 1
      }
      //解锁
      mu.Unlock()

      if num <= 0 {
         break
      }
      //添加休眠,防止结果可能出现在一个goroutine中
      time.Sleep(time.Duration(rand.Int63n(1000) * 1e6))
   }

}

func main() {
   //设置随机数种子
   rand.Seed(time.Now().UnixNano())
   //计算器的起始值和票数相同
   wg.Add(4)
   go sellTicker(1)
   go sellTicker(2)
   go sellTicker(3)
   go sellTicker(4)
   wg.Wait()

   fmt.Println("所有票卖完")
}

二、RWMutex读写锁

RWMutex 源码如下

// There is a modified copy of this file in runtime/rwmutex.go.
// If you make any changes here, see if you should make them there.

// A RWMutex is a reader/writer mutual exclusion lock.
// The lock can be held by an arbitrary number of readers or a single writer.
// The zero value for a RWMutex is an unlocked mutex.
//
// A RWMutex must not be copied after first use.
//
// If a goroutine holds a RWMutex for reading and another goroutine might
// call Lock, no goroutine should expect to be able to acquire a read lock
// until the initial read lock is released. In particular, this prohibits
// recursive read locking. This is to ensure that the lock eventually becomes
// available; a blocked Lock call excludes new readers from acquiring the
// lock.
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
}

Go语言标准库中API如下

type RWMutex
  func (rw *RWMutex) Lock()//禁止其他协程读写
  func (rw *RWMutex) Unlock()
  func (rw *RWMutex) RLock()//禁止其他协程写入,只能读取
  func (rw *RWMutex) RUnlock()
  func (rw *RWMutex) RLocker() Locker
  • Go语言中的map不是线程安全的,多个goroutine同时操作会出现错误.
  • RWMutex可以添加多个读锁或一个写锁.读写锁不能同时存在.
    • map在并发下读写就需要结合读写锁完成
    • 互斥锁表示锁的代码同一时间只能有一个人goroutine运行,而读写锁表示在锁范围内数据的读写操作
package main

import (
   "fmt"
   "sync"
   "strconv"
)

func main() {
   var rwm sync.RWMutex
   m := make(map[string]string)
   var wg sync.WaitGroup
   wg.Add(10)
   for i := 0; i < 10; i++ {
      go func(j int) {
         //没有锁在map时可能出现问题
         rwm.Lock()
         m["key"+strconv.Itoa(j)] = "value" + strconv.Itoa(j)
         fmt.Println(m)
         rwm.Unlock()
         wg.Done()
      }(i)
   }
   wg.Wait()
   fmt.Println("程序结束")
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

书香水墨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值