Skip to content

Instantly share code, notes, and snippets.

@utahcon
Last active May 23, 2016 07:00
Show Gist options
  • Save utahcon/046e5a15aa808f35ce5433eb37235e30 to your computer and use it in GitHub Desktop.
Save utahcon/046e5a15aa808f35ce5433eb37235e30 to your computer and use it in GitHub Desktop.
Below is an example of controlling multiple processes/threads using golang.
package main
import (
"log"
"os"
"os/signal"
"sync"
"time"
)
type MySyncCond struct {
*sync.Cond
Kill bool
Payload int
}
func (m *MySyncCond) Init() {
m.Kill = false
}
// Extend Broadcast to allow a payload
func (m *MySyncCond) Broadcast(payload int) {
// set the new payload before broadcasting
m.Payload = payload
log.Println("Calling real broadcast")
m.Cond.Broadcast()
}
func pinger(c *MySyncCond, wg *sync.WaitGroup) {
defer wg.Done()
defer c.L.Unlock()
defer log.Println("Terminated pinger")
kill := make(chan os.Signal)
signal.Notify(kill)
count := 0
for {
select {
case <-kill:
log.Println("Kill caught")
c.Kill = true
c.Cond.Broadcast()
break
default:
count += 1
log.Printf("Pinger Pings: %d\n", count)
c.Broadcast(count)
time.Sleep(5 * time.Second)
}
}
}
func divByOne(c *MySyncCond, wg *sync.WaitGroup) {
defer wg.Done()
defer log.Printf("Terminated divByOne")
defer c.L.Unlock() // make sure we unlock
for {
c.L.Lock()
c.Wait()
if c.Kill {
break
}
if c.Payload%1 == 0 {
log.Printf("One\n")
}
c.L.Unlock()
}
}
func divByTwo(c *MySyncCond, wg *sync.WaitGroup) {
defer wg.Done()
defer c.L.Unlock() // make sure we unlock
defer log.Println("Terminated divByTwo")
for {
c.L.Lock()
c.Wait()
if c.Kill {
break
}
if c.Payload%2 == 0 {
log.Printf("Two\n")
}
c.L.Unlock()
}
}
func divByThree(c *MySyncCond, wg *sync.WaitGroup) {
defer wg.Done()
defer c.L.Unlock()
defer log.Println("Terminated divByThree")
for {
c.L.Lock()
c.Wait()
if c.Kill {
break
}
if c.Payload%3 == 0 {
log.Printf("Three\n")
}
c.L.Unlock()
}
}
func main() {
logfile, err := os.OpenFile("/tmp/condfun.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
if err != nil {
log.Fatal(err)
}
log.SetOutput(logfile)
defer logfile.Close()
c := MySyncCond{sync.NewCond(new(sync.Mutex)), false, 0}
done := make(chan bool)
kill := make(chan os.Signal)
defer close(kill)
signal.Notify(kill)
var wg sync.WaitGroup
wg.Add(4)
go pinger(&c, &wg)
go divByOne(&c, &wg)
go divByTwo(&c, &wg)
go divByThree(&c, &wg)
go func(wg *sync.WaitGroup, done chan bool) {
defer close(done)
log.Println("Once: Waiting")
wg.Wait()
log.Println("Once: Done")
done <- true
}(&wg, done)
log.Println("Back in main")
<-kill
log.Println("Kill Seen")
c.Kill = true
c.Cond.Broadcast()
log.Println("Terminated Main")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment