Golang竞争状态

看一段代码:

package main

import (
	"fmt"
	"runtime"
	"sync"
)

var (
	counter int
	wg sync.WaitGroup
)

func main() {
	wg.Add(2)

	go incCounter(1)
	go incCounter(2)

	wg.Wait()
	fmt.Println("Final Counter:", counter)
}

func incCounter(id int) {
	defer wg.Done()

	for count := 0; count < 2; count++ {
		value := id

		runtime.Gosched()

		value++
		counter = value
	}
}

goroutine执行的是副本值,然后将副本值写入counter,所以在切换goroutine时,goroutine中的值会覆盖counter。其中Gosched函数是runtime包中用于将goroutine从当前线程退出,给其它goroutine运行的机会。这段代码执行下来理论上应该是存在竞争状态的,对于counter这个变量,在两个goroutine的切换下,一共加了4次,但是由于每次切换后进入队列的并不是真的这个值,而是一个副本,结果输出应该为2。

事实貌似是这样。。。貌似有点小问题。。。

检测竞争状态,再把这个gosched函数注释,然后重新检测竞争状态,先后编译执行得到的是:

为什么会出现这个情况呢?Final Counter: 3

==================
WARNING: DATA RACE
Write at 0x0000005b73c0 by goroutine 6:
  main.incCounter()
      /home/qmq/gopath/src/github.com/goinaction/code/test.go:49 +0x74

Previous write at 0x0000005b73c0 by goroutine 7:
  main.incCounter()
      /home/qmq/gopath/src/github.com/goinaction/code/test.go:49 +0x74

Goroutine 6 (running) created at:
  main.main()
      /home/qmq/gopath/src/github.com/goinaction/code/test.go:25 +0x68

Goroutine 7 (running) created at:
  main.main()
      /home/qmq/gopath/src/github.com/goinaction/code/test.go:26 +0x89
==================
Final Counter: 2
Found 1 data race(s)
==================
WARNING: DATA RACE
Write at 0x0000005b73c0 by goroutine 7:
  main.incCounter()
      /home/qmq/gopath/src/github.com/goinaction/code/test.go:49 +0x74

Previous write at 0x0000005b73c0 by goroutine 6:
  main.incCounter()
      /home/qmq/gopath/src/github.com/goinaction/code/test.go:49 +0x74

Goroutine 7 (running) created at:
  main.main()
      /home/qmq/gopath/src/github.com/goinaction/code/test.go:26 +0x89

Goroutine 6 (finished) created at:
  main.main()
      /home/qmq/gopath/src/github.com/goinaction/code/test.go:25 +0x68
==================
Final Counter: 3
Found 1 data race(s)================

输出小概率有3的情况,可能是goroutine没有退出,所以发生了新goroutine中的值与上一次goroutine副本值相加的情况。对于这样存在多个goroutine对一个共享资源进行操作的功能还是需要对其加锁,或使用简单的atomic。

猜你喜欢

转载自www.cnblogs.com/sigmod3/p/9446080.html