I tried to write sample program with 2 goroutines to illustrate race condition. One print x
, another increment x
.
package main
import (
"fmt"
"time"
)
func main() {
x := 0
go func() {
for {
if x%2 == 0 {
fmt.Println(x)
}
}
}()
go func() {
for {
x = x + 1
}
}()
<-time.After(1 * time.Second)
fmt.Println("final", x)
}
But incremental routine do nothing and finally in x
stays zero. But if incremental routine add fmt.Println(x)
it starts to increment x
and program working as expected.
UPDATE #1:
Purpose of this simple example is only to illustrate data race issue. I know that reading a shared variable between two goroutines without synchronization is a bad idea. Please stop to point me out to that. My question is why incremental goroutine do nothing here? In my picture of the world is should steadily increment, but the issue should appear in the reading goroutine where result may be not determined, because when reading x
is one, but when printing x
may be other.
UPDATE #2:
I have another example:
package main
import (
"time"
"fmt"
)
func main() {
x := 0
go func() {
last := x
for {
current := x
if last != current {
last = current
fmt.Println(last)
}
}
}()
go func() {
for {
//<-time.After(1 * time.Second) // if uncomment this row program start do "something"
x = x + 1
}
}()
<-time.After(10 * time.Second)
fmt.Println("final", x)
}
The example is pretty straightforward. One routine increment counter, other print if changed. This program has undefined behaviour only in the case when writing x = x+1
and read current := x
it is not atomic operation and one thread start read the variable in the middle of writing in the other thread and reading operations will read corrupted value.
But why in this case when uncomment sleep in incremental routine program starts to do something?