英文:
Golang - Why does this race condition occur?
问题
这个程序中的竞争条件是由于对全局变量 glo
的并发访问引起的。在 main
函数中,有一个无限循环,不断向 quit
通道发送数据,并且在每次发送后将 glo
的值加一。同时,在 test
函数中,会打印出 glo
的值。
当 n
的值较小时(如 n := 10000
),两个 goroutine 的执行速度相对较慢,因此在 test
函数中打印出的 glo
的值总是小于等于 n
。
但是,当 n
的值较大时(如 n := 1000000
),两个 goroutine 的执行速度变得更快,它们会更频繁地竞争对 glo
的访问。这就导致了竞争条件,使得 glo
的值可能会超过 n
。
要解决这个竞争条件,你可以使用互斥锁(sync.Mutex
)来保护对 glo
的并发访问。在每次对 glo
的访问之前,先获取锁,然后释放锁。这样可以确保每次只有一个 goroutine 能够访问 glo
,避免竞争条件的发生。
英文:
package main
import "fmt"
var quit chan int
var glo int
func test() {
fmt.Println(glo)
}
func main() {
glo = 0
n := 10000
quit = make(chan int, n)
go test()
for {
quit <- 1
glo++
}
}
Situation:
The above program outputs 10000. But when I assign a bigger number to n (e.g. n := 1000000
), the output will be a random number less than n.
I haven't called runtime.GOMAXPROCS()
, so these two goroutines can't run in parallel. Executing go run -race
to detect race conditions, ends up without any warnings.
Question:
Why does this race condition occur?
答案1
得分: 2
由于main
和test
goroutine之间没有同步,你无法确定test
中的fmt.Println
调用会在什么时候发生。
当使用GOMAXPROCS = 1
运行时,答案实际上取决于调度器何时决定停止执行main
并切换到test
。循环中的发送操作是调度器可以切换到另一个goroutine的一个点,因此通过足够的循环迭代,你可以期望test
在某个时刻有机会执行。它不一定会在每次运行时的相同迭代中切换,这导致结果的变化。
至于使用竞争检测器来捕获此问题,它对我来说成功地捕获了问题:
$ go run -race test.go
==================
WARNING: DATA RACE
Read by goroutine 5:
main.test()
/../test.go:8 +0x6e
Previous write by main goroutine:
main.main()
/.../test.go:18 +0xfe
Goroutine 5 (running) created at:
main.main()
/.../test.go:15 +0x8f
==================
...
英文:
As there is no synchronisation between the main
and test
goroutines, you don't know at what point the fmt.Println
call in test
will happen.
When running with GOMAXPROCS = 1
, the answer will essentially depend on when the scheduler decides to stop executing main
and switch to test
. The send operation within the loop is one point where the scheduler can switch over to another goroutine, so with enough iterations of the loop you'd expect test
to get a chance to execute at some point. It isn't necessarily going to switch at the same iteration every run leading to the variation in results.
As for catching this with the race detector, it successfully catches the problem for me:
$ go run -race test.go
==================
WARNING: DATA RACE
Read by goroutine 5:
main.test()
/../test.go:8 +0x6e
Previous write by main goroutine:
main.main()
/.../test.go:18 +0xfe
Goroutine 5 (running) created at:
main.main()
/.../test.go:15 +0x8f
==================
...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论