HOWTO · Go

GoLang RWMutex

このチュートリアルでは、GoLang で rwmutex を使用する方法を示します。

このページの内容

このチュートリアルでは、GoLang で rwmutex を使用する方法を示します。

GoLang RWMutex

mutex は相互排除の略で、変数にアクセスしたスレッドをいつでも追跡するために使用されます。 ミューテックスは、GoLang の sync パッケージで提供されるデータ構造です。

mutex は、Go コードを使用して同時実行を実行するときに使用されます。 これは、GoLang で mutex を使用する簡単な例です。

package main

import (
    "fmt"
    "sync"
    "time"
)

func EvenNumber(num int) bool {
    return num%2 == 0
}

func main() {
    num := 2
    var DemoMutex sync.Mutex

    go func() {
        DemoMutex.Lock()
        defer DemoMutex.Unlock()
        EvenNum := EvenNumber(num)
        time.Sleep(5 * time.Millisecond)
        if EvenNum {
            fmt.Println("The number", num, " is even")
            return
        }
        fmt.Println("The number", num, "is odd")
    }()

    go func() {
        DemoMutex.Lock()
        num++
        DemoMutex.Unlock()
    }()

    time.Sleep(time.Second)
}

上記のコードは、数値が偶数か奇数かをチェックします。 ここで、同時実行の goroutine はデータを破損する可能性があるため、mutex を使用してデータをロックおよびロック解除し、破損を防ぎます。

出力を参照してください。

The number 2  is even

mutexRWmutex は異なり、mutex は単純なミューテックスであり、RWmutex はリーダー/ライターの相互排他ロックです。 RWMutex を使用すると、ロックは任意の数のリーダーまたは 1つのライターによって保持されます。

RWMutex の値がゼロの場合、ロックされていないミューテックスです。 RWMutexミューテックスで同じ例を試してみましょう。

package main

import (
    "fmt"
    "sync"
    "time"
)

func EvenNumber(num int) bool {
    return num%2 == 0
}

func main() {
    num := 2
    var DemoRWM sync.RWMutex

    // both goroutines call DemoRWM.Lock() before accessing `num` and then call the DemoRWM.Unlock after they are done
    go func() {
        DemoRWM.RLock()
        defer DemoRWM.RUnlock()
        EvenNum := EvenNumber(num)
        time.Sleep(5 * time.Millisecond)
        if EvenNum {
            fmt.Println("The number", num, " is even")
            return
        }
        fmt.Println("The number", num, "is odd")
    }()

    go func() {
        DemoRWM.Lock()
        num++
        DemoRWM.Unlock()
    }()

    time.Sleep(time.Second)
}

ここでわかるように、両方の goroutinesnum にアクセスする前に DemoRWM.Lock() を呼び出し、完了後に DemoRWM.Unlock を呼び出します。 コードは RWMutex を使用しています。

出力を参照してください。

The number 2  is even

RWMutex の別の例を試してみましょう。ここで、RWMutex はすべてのリーダーが同時にデータにアクセスできるようにし、ライターは他のユーザーをロックアウトします。

例を参照してください。

package main

import (
    "fmt"
    "sync"
)

func main() {
    DemoMap := map[int]int{}

    DemoRWM := &sync.RWMutex{}

    go LoopWrite(DemoMap, DemoRWM)
    go LoopRead(DemoMap, DemoRWM)
    go LoopRead(DemoMap, DemoRWM)
    go LoopRead(DemoMap, DemoRWM)
    go LoopRead(DemoMap, DemoRWM)
    go LoopRead(DemoMap, DemoRWM)
    go LoopRead(DemoMap, DemoRWM)
    go LoopRead(DemoMap, DemoRWM)
    go LoopRead(DemoMap, DemoRWM)

    // stop the program from exiting must be killed
    StopBlock := make(chan struct{})
    <-StopBlock
}

func LoopRead(DemoMap map[int]int, DemoRWM *sync.RWMutex) {
    for {
        DemoRWM.RLock()
        for k, v := range DemoMap {
            fmt.Println(k, "-", v)
        }
        DemoRWM.RUnlock()
    }
}
func LoopWrite(DemoMap map[int]int, DemoRWM *sync.RWMutex) {
    for {
        for i := 0; i < 100; i++ {
            DemoRWM.Lock()
            DemoMap[i] = i
            DemoRWM.Unlock()
        }
    }
}

ご覧のとおり、RWMutex を使用すると、read を何度でも使用できます。 このコードの出力は次のようになります。

timeout running program
0 - 0
0 - 0
0 - 0
0 - 0
0 - 0
0 - 0
0 - 0
0 - 0
1 - 1