Mutex
Mutex 用于提供一种加锁机制(Locking Mechanism),可确保在某时刻只有一个协程在临界区运行,以防止出现竞态条件。
Mutex 可以在 [sync] 包内找到。[Mutex] 定义了两个方法:[Lock]和 [Unlock](。所有在 Lock 和 Unlock 之间的代码,都只能由一个 Go 协程执行,于是就可以避免竞态条件。
1
2
3
mutex.Lock()
x = x + 1
mutex.Unlock()
在上面的代码中,x = x + 1 只能由一个 Go 协程执行,因此避免了竞态条件。
如果有一个 Go 协程已经持有了锁(Lock),当其他协程试图获得该锁时,这些协程会被阻塞,直到 Mutex 解除锁定为止。
使用Mutex
package main
import (
"fmt"
"sync"
)
// 使用锁的场景:多个goroutine通过共享内存在实现数据通信
// 临界区:当程序并发地运行时,多个 [Go 协程]同时修改共享资源的代码。这些修改共享资源的代码称为临界区。
//如果在任意时刻只允许一个 Go 协程访问临界区,那么就可以避免竞态条件。而使用 Mutex 可以达到这个目的
//var x = 0 //全局,各个goroutine都可以拿到并且操作
//func increment(wg *sync.WaitGroup,m *sync.Mutex) {
// m.Lock()
// x = x + 1
// m.Unlock()
// wg.Done()
//}
//func main() {
// var w sync.WaitGroup
// var m sync.Mutex //是个值类型,函数传递需要传地址
// fmt.Println(m)
// for i := 0; i < 1000; i++ {
// w.Add(1)
// go increment(&w,&m)
// }
// w.Wait()
// fmt.Println("final value of x", x)
//}
// 通过信道来做
var x = 0
func increment(wg *sync.WaitGroup, ch chan bool) {
ch <- true // 缓冲信道放满了,就会阻塞
x = x + 1
<- ch
wg.Done()
}
func main() {
var w sync.WaitGroup
ch := make(chan bool, 1) //定义了一个有缓存大小为1的信道
for i := 0; i < 1000; i++ {
w.Add(1)
go increment(&w, ch)
}
w.Wait()
fmt.Println("final value of x", x)
}
// 不同goroutine之间传递数据:共享变量, 通过信道
// 如果是修改共享变量,建议加锁
//如果是协程之间通信,用信道