Concurrent access to map

899 views
Skip to first unread message

tang...@gmail.com

unread,
May 16, 2017, 1:10:56 AM5/16/17
to golang-nuts
Hi,

I am aware of golang map is not safe for concurrent access, especially when there is at least one writer.

However, I want to know that if the map has been pre-populated, and different coroutines access (read/write) different key/value pair, is it safe to do so?  There is no deletion or adding keys after the initialization.

I think it should be safe (having been doing this in C++ quite frequently) but just want to double check.  Thanks.

Yan

pierre...@gmail.com

unread,
May 16, 2017, 1:59:29 AM5/16/17
to golang-nuts
Hello,

Once you have written out your values to the map, you can read them concurrently and safely. If you need to write again to it (insert or delete), then you must ensure it is done safely.

Note that, from what I can see in tip, in 1.9 there will be a safe concurrent map: https://tip.golang.org/pkg/sync/#Map.

Egon

unread,
May 16, 2017, 2:01:00 AM5/16/17
to golang-nuts
In Go use `-race` to test safety. (https://blog.golang.org/race-detector)
In C++ use `thread-sanitizer` to test safety. (https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual)

Given the description, it's not safe in Go... and AFAIK, it isn't safe in C++ either.


+ Egon

Val

unread,
May 16, 2017, 3:57:46 AM5/16/17
to golang-nuts
It is not safe to do so and you're understandably asking yourself "but why? my goroutines are working on different already existing entries, so what's going on exactly?".
It turns out that a go builtin map is an opaque stucture that is free to completely reorganize itself at any write operation. Thus, it must be regarded as a whole when thinking about data races. The docs are very explicit about this restriction, and the runtime and the race detector do their best at crashing to guide you into enforcing the rule.

Although it would be "conceivable" for a map to reorganize itself on read operations (say, to move recently or frequently accessed entries to optimized buckets), go builtin maps don't do that and it is safe to have multiple concurrent readers, as long as no writer wolf enters.

HTH
Val

Egon

unread,
May 16, 2017, 6:49:30 AM5/16/17
to golang-nuts


On Tuesday, 16 May 2017 10:57:46 UTC+3, Val wrote:
It is not safe to do so and you're understandably asking yourself "but why? my goroutines are working on different already existing entries, so what's going on exactly?".
It turns out that a go builtin map is an opaque stucture that is free to completely reorganize itself at any write operation. Thus, it must be regarded as a whole when thinking about data races. The docs are very explicit about this restriction, and the runtime and the race detector do their best at crashing to guide you into enforcing the rule.

Although it would be "conceivable" for a map to reorganize itself on read operations (say, to move recently or frequently accessed entries to optimized buckets), go builtin maps don't do that and it is safe to have multiple concurrent readers, as long as no writer wolf enters.

There are additionally subtler issues involved. Because the compiler doesn't know that it is being accessed concurrently, it may make optimizations that are not safe... 

Even a simple example as this will potentially have problems:

var data = map[string]bool{}

func watch() {
var x int
data["running"] = true
for data["running"] {
x++
}
}

func kill() {
time.Sleep(time.Second)
data["running"] = false
}

func main() {
go kill()
watch()
}

This program may or may not terminate... because the compiler is free to optimize watch function as:

func watch() {
var x int
data["running"] = true
        tmp := data["running"]
for tmp {
x++
}
}

+ Egon
Reply all
Reply to author
Forward
0 new messages