Created
January 24, 2017 15:15
-
-
Save gobwas/ac2d0623efe6004a7717e9fd709d3a0c to your computer and use it in GitHub Desktop.
Timer race condition prove.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"flag" | |
"fmt" | |
"sync" | |
"time" | |
) | |
var withLock = flag.Bool("lock", false, "use lock on resets") | |
var withStop = flag.Bool("stop", false, "use stop and channel drain on resets") | |
func main() { | |
flag.Parse() | |
fmt.Printf("lock: %v; stop: %v\n", *withLock, *withStop) | |
var ( | |
resetGoroutines sync.WaitGroup | |
timers sync.WaitGroup | |
delays sync.WaitGroup | |
) | |
var ( | |
startReset = make(chan struct{}) | |
stopReset = make(chan struct{}) | |
) | |
const ( | |
timersCount = 4 | |
resetGoroutinesCount = 32 | |
resetTo = time.Millisecond * 600 | |
resetInterval = resetTo / 6 | |
) | |
timers.Add(timersCount) | |
delays.Add(timersCount) | |
for i := 0; i < timersCount; i++ { | |
go func(x int) { | |
tm := time.AfterFunc(time.Hour, func() { | |
fmt.Printf("timer #%d fired\n", x) | |
delays.Done() | |
}) | |
timers.Done() | |
var mu sync.Mutex | |
resetGoroutines.Add(resetGoroutinesCount) | |
for i := 0; i < resetGoroutinesCount; i++ { | |
go func(i int) { | |
defer resetGoroutines.Done() | |
<-startReset | |
tick := time.NewTicker(resetInterval) | |
for { | |
select { | |
case <-tick.C: | |
if *withLock { | |
mu.Lock() | |
} | |
if *withStop { | |
if !tm.Stop() { | |
select { | |
case <-tm.C: | |
default: | |
} | |
} | |
} | |
tm.Reset(resetTo) | |
if *withLock { | |
mu.Unlock() | |
} | |
case <-stopReset: | |
return | |
} | |
} | |
}(i) | |
} | |
}(i) | |
} | |
timers.Wait() | |
fmt.Printf("initialized %d timers\n", timersCount) | |
close(startReset) | |
fmt.Printf("will sleep for %s x 4 (delay which is set during resets)\n", resetTo) | |
time.Sleep(resetTo * 4) | |
close(stopReset) | |
fmt.Println("done, waiting...") | |
resetGoroutines.Wait() | |
fmt.Println("reset goroutines are done") | |
delays.Wait() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment