A Simple Race Condition in the Go HTTP Handler - Is It Really A Race Condition?
Given the code below, I'm trying to figure out WHY the Go ( go run -race example.go
) race detector is not complaining about a race condition.
var count int
func main() {
http.HandleFunc("/a/", func(w http.ResponseWriter, r *http.Request) {
count++
fmt.Println(count)
})
http.HandleFunc("/b/", func(w http.ResponseWriter, r *http.Request) {
count++
fmt.Println(count)
})
log.Fatal(http.ListenAndServe(":8080", nil))
}
I understand that the Go HTTP server responds to all requests in a separate goroutine. With this in mind, wouldn't the increments made to the global counter by handler functions happen in a goroutine that is separate from the main goroutine and thus constitute a data race?
If this is not a data race, I'd really like to know why.
source to share
This is a race condition. False negatives can happen with race checks.
The race controller is dynamic: instead of checking the source of the problem, it can only see if there are actually reads and writes, without synchronization between them. There is no synchronization operation in your code, but if net/http
it occurs in the increments between increments, it will be fooled. Its author suggests essentially parallel stress tests to get rid of the problems:
- write good parallel tests
- have a continuous assembly with a race detector
- run integration tests
- launch rockets with included canaries into production
In Go 1.4 and below, you must also ensure that your program runs on multiple cores, for example runtime.GOMAXPROCS(runtime.NumCPU())
. In Go 1.5, which will be released in late 2015, GOMAXPROCS will run your code on all available kernels by default.
source to share