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