sync.WaitGroup在结束时报错panic: sync: negative WaitGroup counter

来源:11-2 使用Channel等待任务结束

阿憨阿憨

2019-01-05

老师请问,下面的代码的doWorker中如果继续用

for {
		n := w.in
		fmt.Printf("worker %d received %c \n", id, n)
		w.done()
	}

来打印,会暴出一个恐怖panic.百度了很久说是负于计数器了.
但是这里不是应该和计数器相等的吗?

worker 9 received %!c(chan int=0xc00006e3c0) 
panic: sync: negative WaitGroup counter
worker 1 received %!c(chan int=0xc00006e0c0) 
worker 1 received %!c(chan int=0xc00006e0c0) 

worker 1 received %!c(chan int=0xc00006e0c0) 
goroutine 8 [running]:
worker 1 received %!c(chan int=0xc00006e0c0) 
worker 1 received %!c(chan int=0xc00006e0c0) 
worker 1 received %!c(chan int=0xc00006e0c0) 
sync.(*WaitGroup).Add(0xc00001a080, 0xffffffffffffffff)
	/usr/local/go/src/sync/waitgroup.go:74 +0x137
sync.(*WaitGroup).Done(0xc00001a080)
	/usr/local/go/src/sync/waitgroup.go:99 +0x34

代码

package main

import (
	"fmt"
	"sync"
)

func doWorker(id int, w worker) {
	//这时候就不能用下面这钟方式了,会报错panic: sync: negative WaitGroup counter
	for {
		n := w.in
		fmt.Printf("worker %d received %c \n", id, n)
		w.done()
	}
}

type worker struct {
	in chan int
	done func()
}

func createWorker(id int, wg *sync.WaitGroup) worker {
	w := worker{
		in: make(chan int),
		done: func() {
			wg.Done()
		},
	}
	go doWorker(id, w)
	return w
}

func chanDemo() {
	var wg sync.WaitGroup
	var workers [10]worker
	for i := 0; i < 10; i++ {
		workers[i] = createWorker(i, &wg)
	}
	wg.Add(20)
	for i := 0; i < 10; i++ {
		workers[i].in <- 'a' + i
	}
	for i := 0; i < 10; i++ {
		workers[i].in <- 'A' + i
	}

	wg.Wait()
}

func main() {
	chanDemo()
}

写回答

1回答

ccmouse

2019-01-07

worker 9 received %!c(chan int=0xc00006e3c0)

这个很怪的输出提示了我们这里的值有些问题。%!c的意思是你想以%c的形式输出,但是后面的参数却不是一个%c,也就是不能当做字符输出。为什么呢?n := w.in,这里n是一个channel。我们要做的是从里面获得数据,应该是n:=<-w.in

0
0

Google资深工程师深度讲解Go语言 由浅入深掌握Go语言

语法+分布式爬虫实战 为转型工程师量身打造

5995 学习 · 1909 问题

查看课程