C語言中文網 目錄
首頁 > Go語言教程 > Go語言并發 閱讀:3,473

Go語言互斥鎖(sync.Mutex)和讀寫互斥鎖(sync.RWMutex)

互斥鎖是一種常用的控制共享資源訪問的方法,它能夠保證同時只有一個 goroutine 可以訪問共享資源。在 Go 程序中的使用非常簡單,參見下面的代碼:
package main

import (
    "fmt"
    "sync"
)

var (
    // 邏輯中使用的某個變量
    count int

    // 與變量對應的使用互斥鎖
    countGuard sync.Mutex
)

func GetCount() int {

    // 鎖定
    countGuard.Lock()

    // 在函數退出時解除鎖定
    defer countGuard.Unlock()

    return count
}

func SetCount(c int) {
    countGuard.Lock()
    count = c
    countGuard.Unlock()
}

func main() {

    // 可以進行并發安全的設置
    SetCount(1)

    // 可以進行并發安全的獲取
    fmt.Println(GetCount())

}
代碼說明如下:
  • 第 10 行是某個邏輯步驟中使用到的變量,無論是包級的變量還是結構體成員字段,都可以。
  • 第 13 行,一般情況下,建議將互斥鎖的粒度設置得越小越好,降低因為共享訪問時等待的時間。這里筆者習慣性地將互斥鎖的變量命名為以下格式:

    變量名+Guard

    以表示這個互斥鎖用于保護這個變量。
  • 第 16 行是一個獲取 count 值的函數封裝,通過這個函數可以并發安全的訪問變量 count。
  • 第 19 行,嘗試對 countGuard 互斥量進行加鎖。一旦 countGuard 發生加鎖,如果另外一個 goroutine 嘗試繼續加鎖時將會發生阻塞,直到這個 countGuard 被解鎖。
  • 第 22 行使用 defer 將 countGuard 的解鎖進行延遲調用,解鎖操作將會發生在 GetCount() 函數返回時。
  • 第 27 行在設置 count 值時,同樣使用 countGuard 進行加鎖、解鎖操作,保證修改 count 值的過程是一個原子過程,不會發生并發訪問沖突。

在讀多寫少的環境中,可以優先使用讀寫互斥鎖(sync.RWMutex),它比互斥鎖更加高效。sync 包中的 RWMutex 提供了讀寫互斥鎖的封裝。

我們將互斥鎖例子中的一部分代碼修改為讀寫互斥鎖,參見下面代碼:
var (
    // 邏輯中使用的某個變量
    count int

    // 與變量對應的使用互斥鎖
    countGuard sync.RWMutex
)

func GetCount() int {

    // 鎖定
    countGuard.RLock()

    // 在函數退出時解除鎖定
    defer countGuard.RUnlock()

    return count
}
代碼說明如下:
  • 第 6 行,在聲明 countGuard 時,從 sync.Mutex 互斥鎖改為 sync.RWMutex 讀寫互斥鎖。
  • 第 12 行,獲取 count 的過程是一個讀取 count 數據的過程,適用于讀寫互斥鎖。在這一行,把 countGuard.Lock() 換做 countGuard.RLock(),將讀寫互斥鎖標記為讀狀態。如果此時另外一個 goroutine 并發訪問了 countGuard,同時也調用了 countGuard.RLock() 時,并不會發生阻塞。
  • 第 15 行,與讀模式加鎖對應的,使用讀模式解鎖。

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo