demo1:
const (
THREAD_NUM int = 5
THREAD_PRINT int = 0
THREAD_NEXT_STOPPED int = 1
THREAD_THIS_STOPPED int = 2
)
type Thread_pipline_printer struct {
idx int
status int
next_chan chan int
}
func (printer *Thread_pipline_printer) Print(max_num int, pre Thread_pipline_printer, wg *sync.WaitGroup) {
defer wg.Done()
for {
print_num := <-pre.next_chan
if print_num < max_num {
print_format(printer.idx, print_num)
}
if printer.status == THREAD_PRINT {
printer.next_chan <- (print_num + 1)
}
if print_num > max_num {
printer.status = THREAD_THIS_STOPPED
return
} else if print_num == max_num {//注意。。。。。。。。。。。
printer.status = THREAD_NEXT_STOPPED
}
}
}
func print_format(thread_idx int, print_num int) {
fmt.Printf("Printer%d-%d\n", thread_idx, print_num)
}
func Print() {
printers := make([]Thread_pipline_printer, THREAD_NUM)
for i := 0; i < THREAD_NUM; i++ {
printers[i] =
Thread_pipline_printer{i, THREAD_PRINT, make(chan int)}
}
start := 1
end := 100
wg := &sync.WaitGroup{}
wg.Add(THREAD_NUM)
for i := 0; i < THREAD_NUM; i++ {
input_num := (i + THREAD_NUM - 1) % THREAD_NUM
go printers[i].Print(end+1, printers[input_num], wg)
}
printers[THREAD_NUM-1].next_chan <- start
wg.Wait()
}
这段代码用Chanel将五个协程连接起来,最后注意打印完最后一个数字的协程不能立即关闭,需要将chanel传递一遍依次关闭。否则会造成死锁。
demo2:
func printer(i int, inCh chan int, outCh chan int, endNum int, wg *sync.WaitGroup) {
for {
n, ok := <-inCh
if !ok {
return
}
fmt.Printf("Printer-%d %d\n", i+1, n)
if n == endNum {
wg.Done()
return
}
outCh <- n + 1
}
}
func main() {
const n = 5
const endNum = 100
chs := make([]chan int, n)
for i := 0; i < n; i++ {
chs[i] = make(chan int)
}
wg := &sync.WaitGroup{}
wg.Add(1)
for i := 0; i < n; i++ {
inCh := chs[i]
outCh := chs[(i+1)%n]
go printer(i, inCh, outCh, endNum, wg)
}
chs[0] <- 1
wg.Wait()
for i := 0; i < n; i++ {
close(chs[i])
}
}
这段代码和上边道理是一样的,都是用channel将前后协程连接。这段代码按理说最后是会死锁的(跟第一段代码的注意事项是一个道理)。但是他waitgroup设置的是1,那就是说当有一个协程done了(打印最后一个数字的协程),主协程就不再等待,运行下去结束后其他协程自然会结束。其实第一段代码也可以将waitgroup设置成1,在30行下边加个return,也能跟这段代码一样强制结束。不过这种方式可能不够优雅。