Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go RWMutex still raises race condition?

I have a seemingly innocent package that just makes a slice and protects it with a RWMutex. However, when I run it, it still complains about a race condition. What am I doing wrong? (playground)

type Ids struct {
    e []int64
    sync.RWMutex
}

func (i *Ids) Read() []int64 {
    i.RLock()
    defer i.RUnlock()

    return i.e
}


func (i *Ids) Append(int int64) {
    i.Lock()
    defer i.Unlock()

    i.e = append(i.e, int)
}

func main() {
    t := &Ids{e: make([]int64, 1)}

    for i := 0; i < 100; i++ {
        go func() {
            fmt.Printf("%v\n", t.Read())
        }()

        go func() {
            t.Append(int64(i))
        }()
    }

    time.Sleep(time.Second * 10)
}

when run with -race, it returns (among other things):

==================
WARNING: DATA RACE
Read at 0x00c4200a0010 by goroutine 7:
  main.main.func2()
      .../main.go:38 +0x38

Previous write at 0x00c4200a0010 by main goroutine:
  main.main()
      .../main.go:32 +0x197

Goroutine 7 (running) created at:
  main.main()
      .../main.go:37 +0x173
==================
like image 999
stevenspiel Avatar asked Jan 01 '26 13:01

stevenspiel


1 Answers

You are capturing the same variable i in multiple goroutines.

One way to fix this is to modify your main for loop like so:

for i := 0; i < 100; i++ {
    i := i  # look here
    go func() {
        fmt.Printf("%v\n", t.Read())
    }()

    go func() {
        t.Append(int64(i))
    }()
}

This will ensure that you capture a different variable in the closure of the second goroutine each iteration of the for loop. In your example, the i passed to t.Append was the same i that was incremented by the for loop concurrently.

I also recommend running go vet to catch such errors in the future. For more information, there is an entry on this problem in the Go FAQ that goes into more detail: https://golang.org/doc/faq#closures_and_goroutines

like image 76
Stephen Weinberg Avatar answered Jan 03 '26 12:01

Stephen Weinberg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!