iT邦幫忙

2022 iThome 鐵人賽

DAY 16
1
Software Development

30天學會Golang系列 第 16

Day16 - Go的 Mutex (互斥鎖)

  • 分享至 

  • xImage
  •  

Mutex

根據 參考來源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,但如果要讀取與寫入的話,那就必須把安全性做為第一考量

第16天報到,對 goroutine 中的 channel、WaitGroup 與 Mutex 比較有概念了,之後來出一篇這三種東西的總整理好了

參考來源

  1. https://coding.m.imooc.com/classindex.html?cid=180
  2. https://ithelp.ithome.com.tw/articles/10226885

代碼連結

https://github.com/luckyuho/ithome30-golang/tree/main/day16


上一篇
Day15 - Go的 WaitGroup
下一篇
Day17 - Go的 Select
系列文
30天學會Golang31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言