如何在 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

更新於: 2021年11月1日

317 次瀏覽

開啟你的 職業生涯

透過完成課程獲得認證

開始學習
廣告