多个gotoutine同时操作一个资源,这个资源叫做临界区
在并发条件下,如果多个goroutine在没有相互同步的情况下,访问某个共享的资源,会处于相互竞争的状态,导致并发中的资源/数据竞争问题。如下面的程序,2个goroutine 对count各执行10w 次加一操作,打印出的最终结果很有可能不是20w
package main
import (
"fmt"
"sync"
)
var (
wg sync.WaitGroup
count int
)
func incCount() {
defer wg.Done()
for i := 0; i < 100000; i++ {
count ++
}
}
func main() {
wg.Add(2)
go incCount()
go incCount()
wg.Wait()
fmt.Println(count)
}
执行 go run —race main.go 会告诉你有数据竞争DATA RACE的问题
go run -race main.go
==================
WARNING: DATA RACE
Read at 0x0000005ef648 by goroutine 7:
==================
181708
Found 1 data race(s)
exit status 66
互斥锁同时有且只有一个线程进入临界区,其他的线程则在等待锁,当互斥锁释放后,等待锁的线程才可以获取锁进入临界区,当多个线程同时等待同一个锁,唤醒的策略是随机的
Mutex是互斥锁
// Lock 用于锁住 m,如果 m 已经被加锁,则 Lock 将被阻塞,直到 m 被解锁。
func (m *Mutex) Lock()
// Unlock 用于解锁 m,如果 m 未加锁,则该操作会引发 panic。
func (m *Mutex) Unlock()
eg:
package main
import (
"fmt"
"sync"
)
var (
wg sync.WaitGroup
count int32
mu sync.Mutex
)
func incCount() {
defer wg.Done()
for i := 0; i < 100000; i++ {
mu.Lock()
count++
mu.Unlock()
}
}
func main() {
wg.Add(2)
go incCount()
go incCount()
wg.Wait()
fmt.Println(count)
}
参考
https://draveness.me/golang/docs/part3-runtime/ch06-concurrency/golang-sync-primitives/
http://xiaorui.cc/archives/5951
https://cloud.tencent.com/developer/article/1596863