Reputation: 1399
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
}
https://play.golang.org/p/P5P9Bf5ZSIP
Upvotes: 0
Views: 2440
Reputation: 757
Channel in Go is for sync between two different goroutines. A goroutine would wait read/write unless it finds another goroutine which write/read to the same channel(assuming channel is unbuffered)
That means this program will always have a deadlock :
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, playground")
done := make(chan bool)
done <- true
<- done
}
Because line 10 would be blocked looking for another goroutine which reads from the chan done, but there is no such goroutine.
Hence, writing/reading from the same goroutines would blocks unless there are other goroutines which reads/write from that channel.
Upvotes: 0
Reputation: 3394
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
}
https://play.golang.org/p/QDXuDH0RGPC
Upvotes: 3