如何在 Golang 中使用互斥鎖 (Mutex)?
為了理解 Go 中的 **互斥鎖 (mutex)** 在編寫更出色和準確的併發程式中發揮的重要作用,我們首先必須瞭解稱為 **競爭條件 (Race Conditions)** 的概念。讓我們首先了解什麼是競爭條件,以及如何編寫包含競爭條件的併發程式,以及如何隨後在該程式中引入 **互斥鎖 (mutex)** 以使其準確。
競爭條件
**競爭條件** 是一種狀態,其中多個 **goroutine** 嘗試訪問和修改同一資源。可能的情況是,一個 **goroutine** 試圖增加某個特定變數的值,而另一個 **goroutine** 同時試圖訪問它,或者可能多個 **goroutine** 同時試圖增加某個特定變數的值。
需要注意的是,只有當我們為特定變數提供了 **寫入** 許可權時,才會出現競爭條件。如果只有 **讀取** 許可權可用,那麼就不會有任何問題,因為即使多個 **goroutine** 試圖讀取單個值,讀取也不會導致任何問題。
示例 1
現在假設我們想為一家本地銀行編寫一個應用程式,該銀行只支援將金額存入銀行的單一功能。可能有多個人同時嘗試存入金額,我們可以藉助多個 **goroutine** 來表示這種情況。
請考慮下面顯示的程式碼,該程式碼描述了這種情況。
package main import ( "fmt" "sync" ) var ( balance int wg sync.WaitGroup ) func Deposit(amount int) { balance = balance + amount wg.Done() } func main() { wg.Add(3) go Deposit(100) go Deposit(200) go Deposit(300) wg.Wait() fmt.Println("Balance is:", balance) }
在上面的示例中,我們可以看到除了 **main** 函式 goroutine 之外還有三個 **goroutine**。這三個 **goroutine** 都在呼叫 **deposit** 函式,因此存在競爭條件,因為我們尚未處理它。
可以使用 **"race"** 標誌確認競爭條件的存在。
go run -race main.go
**注意** - **race 標誌** 用於檢查任何 Golang 程式碼是否存在競爭條件。
輸出
Balance is: 600
為了使程式碼更準確並消除此競爭條件,我們使用 **互斥鎖 (Mutex)**,也稱為 **互斥**,它可以防止併發程序在給定程序執行其他任務時訪問關鍵資料。
示例 2
請考慮下面顯示的程式碼,我們在其中在上述程式碼中使用了 **互斥鎖 (Mutex)** 來消除競爭條件。
package main import ( "fmt" "sync" ) var ( balance int wg sync.WaitGroup mu sync.Mutex ) func Deposit(amount int) { mu.Lock() defer mu.Unlock() balance = balance + amount wg.Done() } func main() { wg.Add(3) go Deposit(100) go Deposit(200) go Deposit(300) wg.Wait() fmt.Println("Balance is:", balance) }
輸出
現在,如果我們執行命令 **go run -race main.go**,那麼我們將看不到任何提到的競爭條件。我們得到的輸出如下所示。
Balance is: 600