Skip to content

Instantly share code, notes, and snippets.

@nizhib
Created December 14, 2022 09:43
Show Gist options
  • Save nizhib/5ac7a8c9b24121b405cae24e8c95e97f to your computer and use it in GitHub Desktop.
Save nizhib/5ac7a8c9b24121b405cae24e8c95e97f to your computer and use it in GitHub Desktop.
Synchronizing workers with critical parts
package main
import (
"log"
"math/rand"
"os"
"os/signal"
"sync"
"time"
)
func randomDuration() time.Duration {
return time.Duration(1000+rand.Int63n(1000)) * time.Millisecond
}
func work(job int, done <-chan struct{}, busy *sync.WaitGroup) {
log.Println("downloading", job)
time.Sleep(randomDuration())
log.Println("processing", job)
time.Sleep(randomDuration())
select {
case <-done:
log.Println("skipping", job)
return
default:
busy.Add(1)
log.Println("saving", job)
time.Sleep(randomDuration())
busy.Done()
}
}
func run(jobs <-chan int, done <-chan struct{}, busy *sync.WaitGroup) {
for job := range jobs {
select {
case <-done:
return
default:
work(job, done, busy)
}
}
}
func main() {
workerCount := 4
var wg sync.WaitGroup
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
defer func() {
signal.Stop(interrupt)
}()
done := make(chan struct{}, 1)
var busy sync.WaitGroup
go func() {
select {
case <-interrupt:
close(done)
signal.Stop(interrupt)
log.Println("busy wait")
busy.Wait()
log.Println("busy done")
os.Exit(0)
}
}()
jobs := make(chan int, workerCount)
log.Println("spawning the workers")
wg.Add(workerCount)
for i := 0; i < workerCount; i++ {
go func() {
defer wg.Done()
run(jobs, done, &busy)
}()
}
log.Println("spawning the jobs source")
go func() {
for job := 0; job < 3*workerCount; job++ {
jobs <- job
}
close(jobs)
}()
log.Println("waiting for the workers")
wg.Wait()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment