Skip to content

Instantly share code, notes, and snippets.

@WhisperingChaos
Created April 18, 2018 00:53
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 WhisperingChaos/e66ff57656b520c7df8d4a299d581743 to your computer and use it in GitHub Desktop.
Save WhisperingChaos/e66ff57656b520c7df8d4a299d581743 to your computer and use it in GitHub Desktop.
Goroutine order problem
package main
import (
"fmt"
"strconv"
)
// An alternative to "Synchronization queues in Golang" (https://medium.com/golangspec/synchronization-queues-in-golang-554f8e3a31a4)
// See goplayground ()
func main() {
testersMax := 1000
progrmsMax := 1000
testers := make(chan play, testersMax+100)
progrms := make(chan play, progrmsMax+100)
table := make(chan play)
go playerGen("Tester", testers, testersMax)
go playerGen("Programmer", progrms, progrmsMax)
go playersPair(testers, progrms, table)
term := make(chan bool)
go pingPong(table, 1000, term)
<-term
}
func playerGen(role string, plyq chan<- play, max int) {
for i := 1; i < max+1; i++ {
plr := new(player)
plr.mePlay(role+"_"+strconv.Itoa(i), plyq)
}
}
type play interface {
play() (term chan bool)
}
func pingPong(table <-chan play, maxGames int, term chan<- bool) {
defer func() { term <- true }()
var gameTotal int
fmt.Println()
for {
if gameTotal >= maxGames {
return
}
p1, p1ok := <-table
p2, p2ok := <-table
if !(p1ok && p2ok) {
return
}
p1t := p1.play()
p2t := p2.play()
<-p1t
<-p2t
p1t <- false
p2t <- false
// time.Sleep(100 * time.Millisecond)
gameTotal++
fmt.Println()
}
}
func playersPair(pque1 <-chan play, pque2 <-chan play, table chan<- play) {
pque1sel := pque1
pque2sel := pque2
players := make([]play, 2)
var plyIx int
var ok bool
for {
if plyIx > 1 {
table <- players[0]
table <- players[1]
plyIx = 0
pque1sel = pque1
pque2sel = pque2
}
select {
case players[plyIx], ok = <-pque1sel:
if !ok {
return
}
plyIx++
pque1sel = nil
case players[plyIx], ok = <-pque2sel:
if !ok {
return
}
plyIx++
pque2sel = nil
}
}
}
type player struct {
name string
term chan bool
plyc chan bool
}
func (p *player) mePlay(name string, plyq chan<- play) {
p.name = name
p.term = make(chan bool)
p.plyc = make(chan bool)
start := make(chan bool)
go playerAgent(p, plyq, start)
<-start
close(start)
}
func (p *player) play() (term chan bool) {
fmt.Printf("%s starts\n", p.name)
p.plyc <- true
return p.term
}
func playerAgent(p *player, que chan<- play, start chan bool) {
que <- p
start <- true
for {
// time.Sleep(time.Duration(rand.Intn(50)) * time.Millisecond)
<-p.plyc
// time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond)
fmt.Printf("%s ends\n", p.name)
p.term <- true
que <- p
<-p.term
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment