package main
import "runtime"
var i int
func f(inc int) {
for {
i += inc
}
}
func main() {
runtime.GOMAXPROCS(3)
go f(1)
go f(-1)
runtime.Gosched()
for j := 0; ; j++ {
if (j % 1e9) == 0 {
print(i, "\n")
}
}
}
What I wanted to do was see how things work in the absence of any
events that cause a yield to the scheduler.
Using "ps -elm" I was able to clearly see my three threads spinning
away. Nifty. But the print in main only ever prints 0. It seems
unlikely I'm so unlucky as to never see a -1, or a 1, so I looked a
little closer. What I found in the assembly for f() seems like a bug:
400800 (7) TEXT main.f+0(SB),$34359738368
400800 64488b0c25f0ffffff (7) MOVQ -16(FS),CX
400809 483b21 (7) CMPQ SP,(CX)
40080c 7705 (7) JHI ,400813
40080e e802480000 (7) CALL ,405015+runtime.morestack8
400813 8b4c2408 (7) MOVL main.inc+8(SP),CX
400817 8b042538324100 (7) MOVL main.i+0(SB),AX
40081e 01c8 (9) ADDL CX,AX
400820 ebfc (9) JMP ,40081e
The bug is that main.i is loaded into register CX and incremented
there, instead of being incremented in RAM so that main.main() can see
it get updated. (This is with release.2010-10-13.1.)
The only thing I could find in the spec is that "The scope of an
identifier denoting a constant, type, variable, or function declared
at top level (outside any function) is the package block." So it seems
to me that f(1), f(-1) and main() all should be seeing the *same* i,
and not their own copies of it stored in a register.
What do the Go masters think?
-jeff
but even with more tweaking (see attached), over the long run one
function will be stalled more than the other.
-Skip