Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to recover from concurrent map writes?

How do you recover from a runtime panic on a "concurrent map read and map write"? The usual defer with recover doesn't seem to work. Why is that?

I know that you are not supposed to use maps in concurrent contexts, but still: how to recover here?

Example:

package main

import "time"

var m = make(map[string]string)

func main() {
    go func() {
        for {
            m["x"] = "foo"
        }
    }()
    go func() {
        for {
            m["x"] = "foo"
        }
    }()

    time.Sleep(1 * time.Second)
}

Please add recovery code. :)

like image 706
Igor Lankin Avatar asked Sep 02 '16 09:09

Igor Lankin


1 Answers

Recovering doesn't work here because what you experience is not a panicing state.

Go 1.6 added a lightweight concurrent misuse of maps detection to the 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.

What you experience is an intentional crash by the runtime, it's not the result of a panic() call that a recover() call in a deferred function could stop.

There's nothing you can do to stop that except prevent the concurrent misuse of maps. If you would leave your app like that and it wouldn't crash, you could experience mysterious, undefined behavior at runtime.

like image 129
icza Avatar answered Sep 21 '22 22:09

icza