Help us understand the problem. What is going on with this article?

A Tour of Go の sync.Mutexの例をMutex使わないとどうなるか

More than 1 year has passed since last update.

 目下、職場社内の勉強会でGolangを採り上げており、A Tour of Go を参加者のみんなでざっと追いかけた。その途上で、ふと疑問に思ってちょろっと手を動かしてみたメモ。

 sync.Mutex のコード例 mutex-counter.go で、
「同じことを、Mutexを使わないと失敗するというコードも書いて欲しいなあ」
と思ったんです。
 というのも、RubyのMutexでも、Javaのsynchronizedでも、言語の基本を説明している書籍やサイトでは、たいてい
「排他制御を行わないと、ほら、ダメでしょ?」
という例があったりするもの。
 (たとえば パーフェクトRuby 改訂2版でいえば、P.216 リスト 5.5 「複数のスレッドからcountupメソッドを呼び出す」みたいなやつ)
 なので、mutex-counter.go からmuxをコメントアウトして、以下のようにUnSafeCounterにしてみました。

no-mutex-counter.go
package main

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

// UnSafeCounter is NOT safe to use concurrently.
type UnSafeCounter struct {
    v   map[string]int
    // mux sync.Mutex
}

// Inc increments the counter for the given key.
func (c *UnSafeCounter) Inc(key string) {
    //c.mux.Lock()
    // Lock so only one goroutine at a time can access the map c.v.
    c.v[key]++
    //c.mux.Unlock()
}

// Value returns the current value of the counter for the given key.
func (c *UnSafeCounter) Value(key string) int {
    // c.mux.Lock()
    // Lock so only one goroutine at a time can access the map c.v.
    //defer c.mux.Unlock()
    return c.v[key]
}

func main() {
    c := UnSafeCounter{v: make(map[string]int)}
    for i := 0; i < 1000; i++ {
        go c.Inc("somekey")
    }

    time.Sleep(time.Second)
    fmt.Println(c.Value("somekey"))
}

で、これをgo runしてみると、冒頭に

fatal error: concurrent map writes

と表示され、その後だーっと例外トレースが表示されたのちエラー終了した。

 つらつらと調べていくと、Go 1.6 から、mapを同時に複数のgoroutineから読み書きしようとすると、プログラムがクラッシュするようになったそうだ。

以下、https://golang.org/doc/go1.6#runtime より引用

The runtime has added lightweight, best-effort detection of concurrent misuse of maps. As always, if one goroutine is writing to a map, no other goroutine should be reading or writing the map concurrently. If the runtime detects this condition, it prints a diagnosis and crashes the program. The best way to find out more about the problem is to run the program under the race detector, which will more reliably identify the race and give more detail.

うん、分かった。
気をつけるよ。

補足

JAVAから離れて10年以上経って忘れたけど、JAVAのMap実装のHashMapはどうだったかAPIドキュメントをチラ見すると、

https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html

Note that this implementation is not synchronized. If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the map. If no such object exists, the map should be "wrapped" using the Collections.synchronizedMap method. This is best done at creation time, to prevent accidental unsynchronized access to the map:

Map m = Collections.synchronizedMap(new HashMap(...));

ということで、「HashMapnot synchronized なので、複数のスレッドからひとつのMapへのアクセスがあり得る場合は、Collections.synchronizedMap() でラップしてあげてね」とのことだった。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした