背景
多个协程操作中经常出现脏读写的情况,这种情况下需要使用互斥锁,保证在对协程共享区域操作的原子性。
如下示例:
启动了 100个协程,每个协程累加 100 次,在没有脏读写的情况下,最后结果应该是 100 * 100 = 10000
package main
import (
"fmt"
"sync"
)
func main() {
var count = 0
var wg sync.WaitGroup
wg.Add(100)
for i :=0; i< 100; i++ {
go func(){
defer wg.Done()
for j := 0; j< 100; j ++ {
count ++
}
}()
}
wg.Wait()
fmt.Println(count)
}
但是实际结果一直小于 10000
互斥锁
count ++ 操作, 分为三个步骤
在协程的共享区域取出 count 当前值
当前值加一
加一后的值写回协程共享区域
这时需要使用互斥锁, 来保证对 count++ 的三个操作过程中没有其他协程进行读写。
Go的Sync 包提供了Mutex, 读写互斥的锁, 来保证只有一个协程对数据进行读写操作。 以保证 count++操作的原子性
如下示例:
package main
import (
"fmt"
"sync"
)
func main() {
var count = 0
// 声明Mutex变量
var mu sync.Mutex
var wg sync.WaitGroup
wg.Add(100)
for i :=0; i< 100; i++ {
go func(){
defer wg.Done()
for j := 0; j< 100; j ++ {
// 添加锁
mu.Lock()
count ++
// 解锁
mu.Unlock()
}
}()
}
wg.Wait()
fmt.Println(count)
}
在mu.Lock()
和mu.Unlock()
之间的代码可以保证在操作只会被一个协程执行。这样执行结果就是 10000 了
注意
mu.Lock()
和mu.Unlock()
必须成对出现,在忘掉 Unlock 的情况下,锁获取后永远不会得到释放,其他 的线程/协程会永远处于阻塞状态,永远获取不到锁,在忘掉 Lock 的情况下,直接 Unlock 一个未加锁的 Mutex,会导致程序 panic。
到此这篇关于Go语言中sync.Mutex的使用方法的文章就介绍到这了,更多相关Go sync.Mutex内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!