I am playing around with Goroutines and channels and wonder why I got the error in the title.
The idea is that I have one global int channel that gets incremented per routing.
By using the mutex lock I expected the channel to be locked per routine but that failed.
The code is here:
package main
import (
"fmt"
"sync"
)
var number = make(chan int)
var mutex = &sync.Mutex{}
func worker(wg *sync.WaitGroup, id int) {
defer wg.Done()
mutex.Lock()
number <- id + <-number
mutex.Unlock()
}
func main() {
var wg sync.WaitGroup
number <- 0
for i := 0; i < 5; i++ {
wg.Add(1)
go worker(&wg, i)
}
wg.Wait()
fmt.Println(<-number) // expected output: 0+1+2+3+4 = 10
}
The issue here is to do with the channel you are using as it is unbuffered. An unbuffered channel will block until there is a receiver to receive the message.
Here the main go routine adds a number to the channel then creates the 5 go routines to both take off the channel and add to the channel then waits for them to complete before taking an item off the channel. Adding 0 to the channel will not take place until there is something to receive the number off it so it blocks before it even reaches the mutex.
The 5 go routines can only complete if there is something taking things off the channel.
If you change to a buffered channel by supplying a size to the make call then this starts running to completion:
package main
import (
"fmt"
"sync"
)
var number = make(chan int, 5)
var mutex = &sync.Mutex{}
func worker(wg *sync.WaitGroup, id int) {
defer wg.Done()
mutex.Lock()
number <- id + <-number
mutex.Unlock()
}
func main() {
var wg sync.WaitGroup
number <- 0
for i := 0; i < 5; i++ {
wg.Add(1)
go worker(&wg, i)
}
wg.Wait()
fmt.Println(<-number) // expected output: 0+1+2+3+4 = 10
}