上QQ阅读APP看书,第一时间看更新
8.2.2 sync.RWMutex多读写锁
sync.RWMutex允许读操作并行执行,而写操作仍然是互斥的,通过这种方式可以提高效率。
sync.RWMutex锁是基于sync.Mutex的增强,下面来看一下其结构体:
type RWMutex struct{ w Mutex writerSem uint32 readerSem uint32 readerCount int32 readerWait int32 }
因为sync.RWMutex是对sync.Mutex的增强,而且在其结构体中也确实包含sync.Mutex,所以Mutex的锁还是可以用的,只是RWMutex又多了对读操作的锁定和解锁的操作。
sync.RWMutex除了实现Locker接口以外,还实现了Unlock、RLock和RUnlock接口,下面来看一下RWMutex的四个方法:
func (rw *RWMutex) Lock() func (rw *RWMutex) Unlock() func (rw *RWMutex) RLock() func (rw *RWMutex) RUnlock()
前面两个分别是对写操作的锁定和解锁;后面两个是对读操作的锁定和解锁。RWMutex锁在使用的时候有如下要求:
▪一次只能有一个goroutine获取写锁。
▪可以有多个goroutine同时获取读锁。
▪只能同时获取读锁或者写锁,读和写是互斥的。
在8.2.1节详细介绍了sync.Mutex,所以此处介绍RWMutex就比较简单了,只需看下面的示例:
book/ch08/8.2/RWMutex/rwmutex.go
1. package rwmutex
2.
3. import (
4. "fmt"
5. "sync"
6. "time"
7. )
8.
9. type pass struct {
10. RWM sync.RWMutex
11. pwd string
12. }
13. var RoomPass = pass{pwd:"initPass"}
14.
15. func Change(p *pass,pwd string) {
16. p.RWM.Lock()
17. fmt.Println()
18. time.Sleep(5*time.Second)
19. p.pwd = pwd
20. p.RWM.Unlock()
21. }
22.
23. func getPWD(p *pass) string {
24. p.RWM.RLock()
25. fmt.Println("read pwd")
26. time.Sleep(time.Second)
27. defer p.RWM.RUnlock()
28. return p.pwd
29. }
这里定义一个密码的结构体,里面包含RWMutex锁和一个字符串类型的pwd变量,它们用来记录密码。一般情况下,房间的密码是可以多人读取的,毕竟这个房间可能住了多个人,所以这里使用RWMutex锁。
这时使用了第23行至第29行的getPWD方法。该方法内使用了RWMutex锁,是允许多个goroutine并行读取的。而在第15行至第21行的Change方法用于修改房间密码。注意,只要有人在读,Change方法就会阻塞;同样地,若有人在写,getPWD方法也会阻塞。
这个简单的例子就是对RWMutex的使用,接下来看一下sync.Once锁。