LoginSignup
81
51

More than 5 years have passed since last update.

sync.RWMutexを使おう

Posted at

昨日GoCon2014がありまして、発表の機会を頂いたのですが発表後に @rui314さんから指摘のあったグローバル変数への読み込み・書き込みの競合の問題、これに関してはsync.RWMutexを使うのがいいので、使ってみました。

RLockとLock

通常のsync.MutexはLockのみしか提供しない。これをRead, Write双方で使ってみると非常に効率が悪くなります。そこでsync.RWMutexはRLockというもう一つのLockを提供しています。
この2つの違いは、

  • RLock: Read向けのLock。RLock同士はブロックせず、Lockのみがブロックされる。解除時はUnlockではなくRUnlockする。
  • Lock: いわゆる普通のLock。RLock, Lock双方をブロックする。

上記を使い分けることで効率よくLockを行えるようです。

使ってみる

実際にどう動くのか見るのが分かりやすいと思います。
play.golang.org便利なので貼っときます。
http://play.golang.org/p/JJH3Tm8Sl7

rwmutex.go
package main

import (
    "sync"
    "time"
)

var mu sync.RWMutex
var data map[string]string

func main() {
    data = map[string]string{"hoge": "fuga"}
    mu = sync.RWMutex{}
    go read()
    go read()
    go write()
    go read()
    time.Sleep(5 * time.Second)
}

func read() {
    println("read_start")
    mu.RLock()
    defer mu.RUnlock()
    time.Sleep(1*time.Second)
    println("read_complete", data["hoge"])
}

func write() {
    println("write_start")
    mu.Lock()
    defer mu.Unlock()
    time.Sleep(2 * time.Second)
    data["hoge"] = "piyo"
    println("write_complete")
}
$ go run rwmutex.go
read_start
read_start
write_start
read_start
read_complete fuga
read_complete fuga
write_complete
read_complete piyo

最初のread_complete fugaの部分に関しては、RLockしているので、ほぼ同時に表示されます。
その後write->最後のreadの順にロックが解除されていって実行されています。
上記コードのRLockを全てLock, RUnlockをUnlockに書き換えると挙動の違いが見て分かりやすいかと思います。
http://play.golang.org/p/-w_V4l5K2e

81
51
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
81
51