Reputation: 115
package main
import (
"sync"
"fmt"
)
var m = make(map[string]string)
var seen = make(map[string]bool)
func main() {
wg := new(sync.WaitGroup)
wg.Add(1)
ch := make(chan string)
go deduplicate(ch, wg)
toAdd := []string{"foo", "bar", "baz", "foo"}
for _, s := range toAdd {
ch <- s
}
wg.Wait()
fmt.Println(m)
}
func deduplicate(ch chan string, wg *sync.WaitGroup) {
for s := range ch {
if seen[s] {
wg.Done()
continue
}
seen[s] = true
go write(s)
}
}
func write(s string) {
m[s] = "written"
}
Is the code above safe to use? Note that multiple strings will be written to the map m
concurrently, but they are sure to be unique values, so no string will be written more than once.
Upvotes: 10
Views: 5968
Reputation: 6749
No, that is not safe. It doesn't matter if the keys are unique. You need to avoid concurrent writes or writes concurrent with reads. Concurrent reads are OK.
You can use the race detector to find problems like this by running go run -race myprog.go
. See https://golang.org/doc/articles/race_detector.html.
Upvotes: 6
Reputation: 166549
It is not safe. Go maps are are self-organizing data structures. Run the race detector.
$ go run -race racer.go
==================
WARNING: DATA RACE
Write at 0x00c42007c150 by goroutine 8:
runtime.mapassign_faststr()
/home/peter/go/src/runtime/hashmap_fast.go:598 +0x0
main.write()
/home/peter/gopath/src/racer.go:38 +0x6e
Previous write at 0x00c42007c150 by goroutine 7:
runtime.mapassign_faststr()
/home/peter/go/src/runtime/hashmap_fast.go:598 +0x0
main.write()
/home/peter/gopath/src/racer.go:38 +0x6e
Goroutine 8 (running) created at:
main.deduplicate()
/home/peter/gopath/src/racer.go:33 +0x190
Goroutine 7 (finished) created at:
main.deduplicate()
/home/peter/gopath/src/racer.go:33 +0x190
==================
==================
WARNING: DATA RACE
Write at 0x00c42007c150 by goroutine 9:
runtime.mapassign_faststr()
/home/peter/go/src/runtime/hashmap_fast.go:598 +0x0
main.write()
/home/peter/gopath/src/racer.go:38 +0x6e
Previous write at 0x00c42007c150 by goroutine 7:
runtime.mapassign_faststr()
/home/peter/go/src/runtime/hashmap_fast.go:598 +0x0
main.write()
/home/peter/gopath/src/racer.go:38 +0x6e
Goroutine 9 (running) created at:
main.deduplicate()
/home/peter/gopath/src/racer.go:33 +0x190
Goroutine 7 (finished) created at:
main.deduplicate()
/home/peter/gopath/src/racer.go:33 +0x190
==================
==================
WARNING: DATA RACE
Read at 0x00c42007c150 by main goroutine:
reflect.maplen()
/home/peter/go/src/runtime/hashmap.go:1255 +0x0
reflect.Value.MapKeys()
/home/peter/go/src/reflect/value.go:1090 +0x421
fmt.(*pp).printValue()
/home/peter/go/src/fmt/print.go:739 +0x17fc
fmt.(*pp).printArg()
/home/peter/go/src/fmt/print.go:682 +0x19e
fmt.(*pp).doPrintln()
/home/peter/go/src/fmt/print.go:1136 +0x6e
fmt.Fprintln()
/home/peter/go/src/fmt/print.go:247 +0x65
fmt.Println()
/home/peter/go/src/fmt/print.go:257 +0x78
main.main()
/home/peter/gopath/src/racer.go:23 +0x1c3
Previous write at 0x00c42007c150 by goroutine 7:
runtime.mapassign_faststr()
/home/peter/go/src/runtime/hashmap_fast.go:598 +0x0
main.write()
/home/peter/gopath/src/racer.go:38 +0x6e
Goroutine 7 (finished) created at:
main.deduplicate()
/home/peter/gopath/src/racer.go:33 +0x190
==================
==================
WARNING: DATA RACE
Read at 0x00c42009a088 by main goroutine:
reflect.typedmemmove()
/home/peter/go/src/runtime/mbarrier.go:259 +0x0
reflect.Value.MapIndex()
/home/peter/go/src/reflect/value.go:1069 +0x232
fmt.(*pp).printValue()
/home/peter/go/src/fmt/print.go:750 +0x1867
fmt.(*pp).printArg()
/home/peter/go/src/fmt/print.go:682 +0x19e
fmt.(*pp).doPrintln()
/home/peter/go/src/fmt/print.go:1136 +0x6e
fmt.Fprintln()
/home/peter/go/src/fmt/print.go:247 +0x65
fmt.Println()
/home/peter/go/src/fmt/print.go:257 +0x78
main.main()
/home/peter/gopath/src/racer.go:23 +0x1c3
Previous write at 0x00c42009a088 by goroutine 7:
main.write()
/home/peter/gopath/src/racer.go:38 +0x84
Goroutine 7 (finished) created at:
main.deduplicate()
/home/peter/gopath/src/racer.go:33 +0x190
==================
map[foo:written bar:written baz:written]
Found 4 data race(s)
exit status 66
Upvotes: 3