Search code examples
goconcurrencygoroutine

What happens if concurrent processes write to a global variable the same value?


I'm just wondering if there is potential for corruption as a result of writing the same value to a global variable at the same time. My brain is telling me there is nothing wrong with this because its just a location in memory, but I figure I should probably double check this assumption.

I have concurrent processes writing to a global map var linksToVisit map[string]bool. The map is actually tracking what links on a website need to be further crawled.

However it can be the case that concurrent processes may have the same link on their respective pages and therefore each will mark that same link as true concurrently. There's nothing wrong with NOT using locks in this case right? NOTE: I never change the value back to false so either the key exists and it's value is true or it doesn't exist.

I.e.

var linksToVisit = map[string]bool{}

... 
// somewhere later a goroutine finds a link and marks it as true
// it is never marked as false anywhere
linksToVisit[someLink] = true 

Solution

  • What happens if concurrent processes write to a global variable the same value?

    The results of a data race are undefined.

    Run the Go data race detector.

    References:

    Wikipedia: Race condition

    Benign Data Races: What Could Possibly Go Wrong?

    The Go Blog: Introducing the Go Race Detector

    Go: Data Race Detector


    Go 1.8 Release Notes

    Concurrent Map Misuse

    In Go 1.6, the runtime added lightweight, best-effort detection of concurrent misuse of maps. This release improves that detector with support for detecting programs that concurrently write to and iterate over a map.

    As always, if one goroutine is writing to a map, no other goroutine should be reading (which includes iterating) 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.


    For example,

    package main
    
    import "time"
    
    var linksToVisit = map[string]bool{}
    
    func main() {
        someLink := "someLink"
        go func() {
            for {
                linksToVisit[someLink] = true
            }
        }()
        go func() {
            for {
                linksToVisit[someLink] = true
            }
        }()
        time.Sleep(100 * time.Millisecond)
    }
    

    Output:

    $ go run racer.go
    fatal error: concurrent map writes
    $
    
    $ go run -race racer.go
    
    ==================
    WARNING: DATA RACE
    Write at 0x00c000078060 by goroutine 6:
      runtime.mapassign_faststr()
          /home/peter/go/src/runtime/map_faststr.go:190 +0x0
      main.main.func2()
          /home/peter/gopath/src/racer.go:16 +0x6a
    
    Previous write at 0x00c000078060 by goroutine 5:
      runtime.mapassign_faststr()
          /home/peter/go/src/runtime/map_faststr.go:190 +0x0
      main.main.func1()
          /home/peter/gopath/src/racer.go:11 +0x6a
    
    Goroutine 6 (running) created at:
      main.main()
          /home/peter/gopath/src/racer.go:14 +0x88
    
    Goroutine 5 (running) created at:
      main.main()
          /home/peter/gopath/src/racer.go:9 +0x5b
    ==================
    
    fatal error: concurrent map writes
    
    $