Li Zhang
5 min readAug 24, 2020

--

问题:
甜筒店里进来10个顾客,每个顾客(customer)购买若干个甜筒(cone),可以假设最少购买1个,最多购买4个。
每一个甜筒都需要一个店员(clerk)去做(假设clerk的数量足够多),店员做完每一个甜筒之后,
需要向经理(manager)申请检测,检测合格后才可以交给顾客。
但是经理每次只能接受一个店员的申请,检测一个甜筒,并以一定的概率通过这个甜筒是否合格。
经理需要等到所有顾客要求的甜筒合格后才可以下班走人。顾客等待他所需要的所有的甜筒做完之后,
他要去收银员(cashier)那里付钱。顾客必须排队,而收银员按照排队的顺序依次给顾客结账。顾客结完账后可以顺利走人。

package main

import (
"fmt"
"math/rand"
"sync"
"time"
)


func randInt(min, max int) int {
rand.Seed(time.Now().UnixNano())

r := rand.Intn(max - min)
return min + r
}

const (
minCones = 1
maxCones = 4
numC = 10
)

var managerChan = make(chan struct{}, 1) // 每次只有一个clerk可以让manager检查
var coneChan = make(chan string) // 唤醒manager检查甜筒
var conePass = make(chan int) // clerk得知甜筒是否合格的通道
var goHome = make(chan struct{}) // 通知manager回家的信号
var cashierQueue = make(chan *chan string, numC) // cashier的收银队列,先进先出
var end = make(chan struct{})

func cashier() {
for i := 0; i < numC; i++ {
ch := <-cashierQueue
fmt.Printf("cahier is doing %dth customer\n", i)
(*ch) <- "payed"
}
close(cashierQueue)
end <- struct{}{}

}

func manager() {
for {
select {
case s := <-coneChan:
fmt.Printf("manager is inspecting %s\n", s)

conePass <- randInt(0, 2)

case <-goHome:
fmt.Printf("manager GO Home\n")
return
}
}
}

func clerk(id int, i int, ch chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("clerk is doing customer's (id %d) %dth cones\n", id, i)
time.Sleep(time.Duration(rand.Intn(3)) * time.Second)
for {
//
managerChan <- struct{}{}
s := fmt.Sprintf("customer's (id %d) %dth cones", id, i)
coneChan <- s
pass := <-conePass
if pass > 0 {
fmt.Printf("%s, is PASS\n", s)
ch <- i
<-managerChan
return
}
fmt.Printf("%s, is NOT PASS\n", s)
<-managerChan
}

}

func customer(id int, wgc *sync.WaitGroup) {
n := randInt(minCones, maxCones+1)
ch := make(chan int, n)

fmt.Printf("customer %d: buy %d cones\n", id, n)
var wg sync.WaitGroup
for i := 0; i < n; i++ {
wg.Add(1)
tmp := i
go clerk(id, tmp+1, ch, &wg)
}

go func() {
wg.Wait()
close(ch)
}()

for i := range ch {
fmt.Printf("customer's (id %d) %dth cones is Done\n", id, i)
}

wgc.Done()

// go to cashier
q := make(chan string)
cashierQueue <- (&q)
fmt.Printf("customer's (id %d) is %s, GO HOME!\n", id, <-q)

}

func main() {
go cashier()
go manager()
var wg sync.WaitGroup
for i := 0; i < numC; i++ {
id := i
wg.Add(1)
go customer(id, &wg)
}

go func() {
wg.Wait()
goHome <- struct{}{}
}()

<-end

}

--

--