Skip to content

Instantly share code, notes, and snippets.

@ezdiy
Created September 22, 2019 17:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ezdiy/7be7d161f75980980fd5bdfc5dffa42b to your computer and use it in GitHub Desktop.
Save ezdiy/7be7d161f75980980fd5bdfc5dffa42b to your computer and use it in GitHub Desktop.
// Bug - this program should terminate. It doesn't. Why?
package main
import (
"log"
"runtime"
"sync"
"sync/atomic"
)
const forceSchedule = false
func main() {
var stop uint32
var wg sync.WaitGroup
wg.Add(1)
// Pure compute goroutine which doesn't spam gc, doesn't talk to mutexes, nor does any I/O. It merely
// checks atomic flag to be told to stop computing.
go func() {
for atomic.LoadUint32(&stop) == 0 {
// If forceSchedule is true, everything works fine.
// It seems that scheduler at the other end simply presumes that it will get an in to
// here *eventually*. But that creates a deadlock condition - scheduler own's waiting for
// this chance stops this goroutine from that chance (by setting stop=1) to happen.
if forceSchedule {
runtime.Gosched()
}
}
log.Println("compute terminating")
wg.Done()
}()
// This is a manager goroutine which does normal go stuff, networking io, generating garbage etc.
// eventually it tells the compute goroutine to halt.
var y *int
for x := 0; x < 1000000; x++ {
// trigger gc which seems to trip mcall() to scheduler and that gets stuck
// on the compute goroutine. This thread now hangs here on a mutex waiting for compute goroutine to schedule,
// thus barring us from delivering stop condition allowing the schedule in the first place.
y = new(int)
}
_ = y
atomic.StoreUint32(&stop, 1)
wg.Wait()
log.Println("done")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment