Go言語でマルチスレッドで共有変数をどのように実装するか

Go言語では sync パッケージの Mutex や RWMutex を利用して、複数の goroutine で共有する変数のアクセス制御を行うことができる。

Mutexは共有変数への読み書きアクセスを制御するための排他制御手段であり、LockメソッドとUnlockメソッドを使用して制御します。Lockメソッドを使用する前にロックを取得する必要がありますが、Unlockメソッドを使用してロックを解放するときにロックを取得する必要はありません。

import (
    "sync"
)

var (
    mu sync.Mutex
    count int
)

func main() {
    go increment()
    go increment()

    // 等待所有goroutine执行完成
    time.Sleep(time.Second)

    fmt.Println("count:", count)
}

func increment() {
    for i := 0; i < 100000; i++ {
        mu.Lock()
        count++
        mu.Unlock()
    }
}

RWMutexは読み取り書き込みロックで、複数のgoroutineが共有変数の読み取りが同時にできますが、書き込み操作は1つのgoroutineのみが可能です。RLockおよびRUnlockメソッドを使用して読み取りロックを取得および解除し、LockおよびUnlockメソッドを使用して書き込みロックを取得および解除します。

import (
    "sync"
)

var (
    mu sync.RWMutex
    count int
)

func main() {
    go read()
    go read()
    go write()

    // 等待所有goroutine执行完成
    time.Sleep(time.Second)

    fmt.Println("count:", count)
}

func read() {
    for i := 0; i < 100000; i++ {
        mu.RLock()
        _ = count
        mu.RUnlock()
    }
}

func write() {
    for i := 0; i < 100000; i++ {
        mu.Lock()
        count++
        mu.Unlock()
    }
}

sync.Mutex や sync.RWMutex を使う際には、以下を注意してください。

  1. LockまたはRLockメソッドでロックを取得しようとすると、そのロックが他のゴルーチンでロックされている場合、そのゴルーチンはロックが解放されるまで待機します。
  2. ロックを解放する前に、共有変数の読み書き処理が終わっていることを確認し、データ不整合を回避してください。
  3. defer文を用いることで、関数の返却時にロックを解放し、ロックの解放忘れによるデッドロックを防ぐことができる。
bannerAds