Counter records things remaining to process. It is needed for complicated cases where multiple goroutines are spawned to process items, and they may generate more items to process. For example, say a query over a set of nodes may yield either a result value, or more nodes to query. Signaling is subtly complicated, because the queue may be empty while items are being processed, that will end up adding more items to the queue.

Use Counter like this:

todos := make(chan int, 10)
ctr := todoctr.NewCounter()

process := func(item int) {
  fmt.Println("processing %d\n...", item)

  // this task may randomly generate more tasks
  if rand.Intn(5) == 0 {
    todos<- item + 1
    ctr.Increment(1) // increment counter for new task.

  ctr.Decrement(1) // decrement one to signal the task being done.

// add some tasks.
todos<- 1
todos<- 2
todos<- 3
todos<- 4

for {
  select {
  case item := <- todos:
    go process(item)
  case <-ctr.Done():
    fmt.Println("done processing everything.")

Counter is referenced in 2 repositories