title: Golang race condition when sharing channel across parallel goroutines
body: <p>I'm writing this example code to teach myself how to share channels across parallel goroutines and I'm hitting a race condition. The program should start as many goroutines as there are available CPUs on the system. The first goroutine to access the bl channel immediately sets the channel to contain false so that no other goroutines can access the loop that ranges over the st channel. The other goroutines should end as the first goroutine that accessed the bl channel reads from the st channel and prints each value.</p>
  
  <pre><code>package main
  
  import (
      "fmt"
      "runtime"
      "strconv"
      "math/rand"
      "time"
      "sync"
  )
  
  func main () {
      runtime.GOMAXPROCS(runtime.NumCPU())
      var wg sync.WaitGroup
      st := make(chan string)
      bl := make(chan bool)
      go func() {bl &lt;- true}()
  
      for i := 0; i &lt; runtime.NumCPU(); i++ {
          wg.Add(1)
          go func(x int) {
              defer wg.Done()
              fmt.Println("me: ", strconv.Itoa(x))
  
              can := &lt;- bl
              bl &lt;- false
  
              if can {
                  for val := range st {
                      t      := strconv.Itoa(rand.Int()%3)+"s"
                      dur, _ := time.ParseDuration(t)
                      time.Sleep(dur)
  
                          fmt.Println("time: ", t," i: ", strconv.Itoa(x), val)
                  }
              }
              fmt.Println("done: ", strconv.Itoa(x))
          }(i)
      }
  
      for i := 0; i &lt; 10; i++ {
          st &lt;- "n: "+strconv.Itoa(i)
      }
  
      wg.Wait()
      close(st)
  }
  </code></pre>
  
  <p>When I run the code, I get the following error:</p>
  
  <pre><code>$ go run share.go 
  me:  1
  me:  0
  me:  2
  me:  3
  done:  0
  done:  2
  time:  2s  i:  1 n: 0
  time:  1s  i:  1 n: 1
  time:  0s  i:  1 n: 2
  time:  2s  i:  1 n: 3
  time:  2s  i:  1 n: 4
  time:  2s  i:  1 n: 5
  time:  0s  i:  1 n: 6
  time:  2s  i:  1 n: 7
  time:  2s  i:  1 n: 8
  time:  2s  i:  1 n: 9
  fatal error: all goroutines are asleep - deadlock!
  
  goroutine 1 [semacquire]:
  sync.runtime_Semacquire(0xc4200701bc)
      /usr/local/go/src/runtime/sema.go:47 +0x30
  sync.(*WaitGroup).Wait(0xc4200701b0)
      /usr/local/go/src/sync/waitgroup.go:131 +0x97
  main.main()
      /share.go:80 +0x1ef
  
  goroutine 36 [chan receive]:
  main.main.func2(0xc4200701b0, 0xc42006e0c0, 0xc42006e060, 0x1)
      /share.go:64 +0x23e
  created by main.main
      /share.go:73 +0x127
  
  goroutine 38 [chan send]:
  main.main.func2(0xc4200701b0, 0xc42006e0c0, 0xc42006e060, 0x3)
      /share.go:61 +0x1ef
  created by main.main
      /share.go:73 +0x127
  exit status 2
  </code></pre>
  
  <p>I'm not sure how to handle this race condition for the bl channel. It seems that the last goroutine is stuck trying to read from the bl channel but there's nothing for it to read because the goroutine before it hasn't inserted <code>false</code> yet. Not sure if my intuition is correct. I placed print lines around the code and that's what seems to be happening at least. I also tried putting an if around the bl channel, but that ended up with the same issue. I also moved <code>bl &lt;- false</code> inside the <code>if can {</code> block, but that didn't work either. How do I fix this?</p>