根據 參考來源2,用於並發時,對於共享資源的保護機制,也就是加上互斥鎖,當其中一個線程在訪問資源時將之上鎖,不允許其他線程訪問。下面有個還沒有家 Mutex 的簡單範例:
type atomicInt int
func (a *atomicInt) increment() {
*a++
}
func (a *atomicInt) get() int {
return int(*a)
}
func main() {
var a atomicInt
a.increment()
go func() {
for {
a.increment()
}
}()
time.Sleep(time.Millisecond)
fmt.Println(a)
}
在終端機中輸入 go run -race day16.go,使用 -race 是為了要查看讀取與寫入會不會有可能發生衝突的檢視方式,輸出結果為:
==================
WARNING: DATA RACE
Read at 0x00c000134018 by main goroutine:
...
==================
125683
Found 1 data race(s)
exit status 66
當有 WARNING: DATA RACE 發生時,就表示有機率在讀寫時發生衝突,也就是在 day12 提到的情況,為了避免這種情況發生,我們前面提到了 channel 與 WaitGroup 的方式,那今天就是要介紹 Mutex 的方式,簡單來說,就是有一個線程今天訪問了某個 function ,可以先上鎖,使其他線程無法訪問,直到這個線程訪問結束解鎖後,其他線程才能訪問
那加上 Mutex 的寫法如下:
type atomicInt struct {
val int
lock sync.Mutex
}
// func (a *atomicInt) increment() {
a.lock.Lock()
defer a.lock.Unlock()
a.val++
// }
// func (a *atomicInt) get() int {
a.lock.Lock()
defer a.lock.Unlock()
return a.val
// }
// func main() {
// var a atomicInt
// a.increment()
// go func() {
// for {
// a.increment()
// }
// }()
// time.Sleep(time.Millisecond)
fmt.Println(a.get())
// }
在終端機中輸入 go run -race day16.go,輸出結果為:
1751
可以看到輸出結果沒有 WARNING: DATA RACE 等字樣,不過也可以注意到 a 的輸出結果確實也差了很多,從 125683 變成 1751,表示用效率換取安全性,所以在不同情境可以選擇不同的使用工具,假設單純讀取的話,其實可以單純使用 groutine 而不用 Mutex,但如果要讀取與寫入的話,那就必須把安全性做為第一考量
https://github.com/luckyuho/ithome30-golang/tree/main/day16