Go语言中的普通锁Mutex和读写锁RWMutex

一、普通锁Mutex

1.1 原型

type Mutex struct {
    state int32
    sema uint32
}

  • Mutex是⼀个互斥锁,可以创建为其他结构体的字段;零值为解锁状态。Mutex类型的锁和线程⽆关,可以由不同的线程加锁和解锁。

1.2 Mutex中的方法

  • func (m *Mutex) Lock()
    Lock⽅法锁住m,如果m已经加锁,则阻塞直到m解锁。
  • func (m *Mutex) Unlock()
    Unlock⽅法解锁m,如果m未加锁会导致运⾏时错误。锁和线程无关,可以由不同的线程加锁和解锁。

    案例1.用普通锁来实现火车站卖票
//myMutexTick.go

// myMutexDes project main.go
package main

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

//全局变量
var ticks = 100
var wg sync.WaitGroup
var mutex sync.Mutex

func saleTickets(name string, wg *sync.WaitGroup) {
	for {
		mutex.Lock()
		if ticks > 0 {
			time.Sleep(200 * time.Microsecond)
			fmt.Println(name, ": ", ticks)
			ticks--
		} else {
			fmt.Println(name, "结束卖票...")
			mutex.Unlock()
			break
		}
		mutex.Unlock()
	}
	wg.Done() //通知计数器减一
}

func main() {
	//模拟火车站卖票
	//火车票一共100张,4个售票口出售(相当于4个子协程)

	var wg sync.WaitGroup
	wg.Add(4)
	go saleTickets("售票口A ", &wg)
	go saleTickets("售票口B ", &wg)
	go saleTickets("售票口C ", &wg)
	go saleTickets("售票口D ", &wg)

	wg.Wait()
	fmt.Println("所有车票已售空,程序结束!")
}


    效果如下:


图(1)用Mutex模拟火车站卖票

二、读写锁RWMutex

2.1 原型

type RWMutex struct {
    w Mutex
    writerSem uint32
    readerSem uint32
    readerCount int32
    readerWait int32
}

  • RWMutex是读写互斥锁。该锁可以被同时多个读取者持有或唯⼀个写⼊者持有。 RWMutex可以创建为其他结构体的字段;零值为解锁状态。 RWMutex类型的锁也和线程⽆关,可以由不同的线程加读取锁/写⼊和解读取锁/写⼊锁。
  • 锁定的规则:
    a) 读写锁的使⽤中:写操作都是互斥的、读和写是互斥的、读和读不互斥。
    b) 可以多个goroutine同时读取数据但只允许⼀个goroutine写数据

2.2 RWMutex中的方法

  • func (rw *RWMutex) Lock()
    Lock⽅法将rw锁定为写⼊状态,禁⽌其他线程读取或者写⼊。
  • func (rw *RWMutex) Unlock()
    Unlock⽅法解除rw的写⼊锁状态,如果m未加写⼊锁会导致运⾏时错误。
  • func (rw *RWMutex) RLock()
    RLock⽅法将rw锁定为读取状态,禁⽌其他线程写⼊,但不禁⽌读取。
  • func (rw *RWMutex) RUnlock()
    Runlock⽅法解除rw的读取锁状态,如果m未加读取锁会导致运⾏时错误。
  • func (rw *RWMutex) RLocker() Locker
    Rlocker⽅法返回⼀个互斥锁,通过调⽤rw.Rlock和rw.Runlock实现了Locker接⼝。

    案例2. 主线程加锁、解锁子协程
//myMutexWrite.go

// myMutexWrite project main.go
package main

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

func main() {
	var rwm sync.RWMutex
	for i := 1; i <= 3; i++ {
		go func(i int) {
			fmt.Printf("goroutine %d, 尝试读锁定", i)
			rwm.RLock()
			fmt.Printf("goroutine %d, 已经读锁定了...\n", i)
			time.Sleep(3 * time.Second)
			fmt.Printf("goroutine %d, 读解锁...\n", i)
			rwm.RUnlock()
		}(i)
	}

	time.Sleep(1 * time.Second)
	fmt.Println("main 尝试写锁定...")
	rwm.Lock()
	fmt.Println("main 已经写锁定了...")
	rwm.Unlock()
	fmt.Printf("main 写解锁...")
}


    效果如下:


图(2) 主线程加锁、解锁子协程
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值