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

    科技2022-07-15  118

    一、普通锁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) 主线程加锁、解锁子协程
    Processed: 0.014, SQL: 8