Golang 锁
锁
sync
包中 Locker 提供互斥锁(Mutex
)和读写锁(RWMutex
)
-
为什么要锁
go run test1.go |sort|uniq |wc -l
会发现下面代码明明是递增 但是结果会出现最后可能不是999
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
package main import ( "fmt" "time" ) func main() { var a = 0 for i := 0; i < 999; i++ { go func(idx int) { a += 1 fmt.Println(a) }(i) } time.Sleep(time.Second) }
-
怎么解决以上问题
可是使用锁来实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
package main import ( "fmt" "sync" "time" ) func main() { var a = 0 var lock sync.Mutex for i := 0; i < 999; i++ { go func(idx int) { lock.Lock() defer lock.Unlock() a += 1 fmt.Println(a) }(i) } // 等待 1s 结束主程序 // 确保所有协程执行完 time.Sleep(time.Second) }
互斥锁(Mutex
)
只能有一个线程占用资源,其他线程只能等待
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main
import (
"fmt"
"sync"
)
var mutex sync.Mutex
func printFunc(str string) {
mutex.Lock()
defer mutex.Unlock()
for _, data := range str {
fmt.Printf("%c", data)
}
fmt.Println()
}
func main() {
var waitGroup sync.WaitGroup
waitGroup.Add(2)
go func() {
defer waitGroup.Done()
printFunc("hello")
}()
go func() {
defer waitGroup.Done()
printFunc("world")
}()
waitGroup.Wait()
}
读写锁(RWMutex
)
读写
-
写操作的锁定和解锁
- func (*RWMutex) Lock
-
func (*RWMutex) Unlock
- 读操作的锁定和解锁
- func (*RWMutex) Rlock
- func (*RWMutex) RUnlock
前言
当有一个 goroutine 获得写锁定,其它无论是读锁定还是写锁定都将阻塞直到写解锁;当有一个 goroutine 获得读锁定,其它读锁定仍然可以继续;当有一个或任意多个读锁定,写锁定将等待所有读锁定解锁之后才能够进行写锁定。所以说这里的读锁定(RLock)目的其实是告诉写锁定:有很多人正在读取数据,你给我站一边去,等它们读(读解锁)完你再来写(写锁定)。我们可以将其总结为如下三条:
- 同时只能有一个
goroutine
能够获得写锁定 - 同时可以有任意多个
gorouinte
获得读锁定 -
同时只能存在写锁定或读锁定(读和写互斥)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
package main import ( "fmt" "sync" "time" ) var str = "Hello World" var rw sync.RWMutex func main() { go func() { for i := 0; i < 100; i++ { read() } }() go func() { for i := 0; i < 1; i++ { write("write") } }() time.Sleep(time.Second * 2) } // 读 func read() { rw.RLock() defer rw.RUnlock() fmt.Println("读", str) } // 写 func write(n string) { rw.Lock() defer rw.Unlock() str += "no HelloWorld " + n fmt.Println("写", str) for i := 0; i < 100; i++ { fmt.Println("在写入请等下") } }
This post is licensed under
CC BY 4.0
by the author.