Deadlock error when trying to sync goroutines - go

I'm facing an annoying problem. When I try to use wg.Add() to sync my routines, a deadlock error is raised.
package main
import (
"fmt"
"sync"
)
func hello(ch chan int, num int, wg *sync.WaitGroup) {
for {
i := <-ch
if i == num {
fmt.Println("Hello number:", i)
ch <- (num - 1)
defer wg.Done() // Same happens without defer
return
}
ch <- i
}
}
func main() {
fmt.Println("Start")
var wg sync.WaitGroup
ch := make(chan int)
for i := 0; i < 10; i++ {
wg.Add(1)
go hello(ch, i, &wg)
}
ch <- 9
wg.Wait()
fmt.Println("End")
}
Outputs:
Start
Hello number: 9
Hello number: 8
Hello number: 7
Hello number: 6
Hello number: 5
Hello number: 4
Hello number: 3
Hello number: 2
Hello number: 1
Hello number: 0
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc04203a20c)
C:/Go/src/runtime/sema.go:47 +0x3b
sync.(*WaitGroup).Wait(0xc04203a200)
C:/Go/src/sync/waitgroup.go:131 +0x81
main.main()
C:/Users/Augusto Dias/Documents/GoLang/MT.go:34 +0x1a0
goroutine 18 [chan send]:
main.hello(0xc0420380c0, 0x0, 0xc04203a200)
C:/Users/Augusto Dias/Documents/GoLang/MT.go:13 +0x197
created by main.main
C:/Users/Augusto Dias/Documents/GoLang/MT.go:29 +0x151
exit status 2
When I use wg.Add(9) outside the for block, I got no error.
func main() {
fmt.Println("Start")
var wg sync.WaitGroup
ch := make(chan int)
wg.Add(9) // Use wg.Add(10) will raise deadlock too
for i := 0; i < 10; i++ {
go hello(ch, i, &wg)
}
ch <- 9
wg.Wait()
fmt.Println("End")
}
Outputs:
Start
Hello number: 9
Hello number: 8
Hello number: 7
Hello number: 6
Hello number: 5
Hello number: 4
Hello number: 3
Hello number: 2
Hello number: 1
End
Why is this happening, I mean, why routines goes asleep when I wait for them all? Use the same channel for send and receive can be the source of this problem?

Channel 0 (the call go hello(ch, 0, &wg)) since it is the last channel alive gets stuck on this line
ch <- (num - 1)
It is attempting to send to a channel but no one is there to receive it. Thus the function will wait indefinitely and never be done.
Some suggestions for how to remove this problem
create a consumer in the main loop
make the channel ch non blocking

Related

issue with go routine and channel

I am learning go routines and channels,here is a basic program which i tried on the topic ,I am getting error that fatal error: all goroutines are asleep - deadlock! and I also want to know why length of my channel is zero.
package main
import (
"fmt"
)
func main() {
mychannel := make(chan int)
go takeChn(mychannel)
fmt.Println("length", len(mychannel))
for res := range mychannel {
fmt.Println("firstFunc", res, len(mychannel))
}
}
func takeChn(c chan int) {
for i := 0; i < 10; i++ {
c <- (i + 1)
}
}
The length of the channel is zero, because it is an unbuffered channel. It does not store any elements.
Your program deadlocks because the for-loop never terminates. The range over the channel will terminate when the channel is closed, but you never close the channel.
If you close the channel at the end of the goroutine, the program will run without a deadlock.
Modifying the code as per Burak Serdar's input by closing the channel
package main
import (
"fmt"
)
func main() {
mychannel := make(chan int)
go takeChn(mychannel)
fmt.Println("length", len(mychannel))
for res := range mychannel {
fmt.Println("firstFunc", res, len(mychannel))
}
}
func takeChn(c chan int) {
for i := 0; i < 10; i++ {
c <- (i + 1)
}
close(c)
}
Output:
length 0
firstFunc 1 0
firstFunc 2 0
firstFunc 3 0
firstFunc 4 0
firstFunc 5 0
firstFunc 6 0
firstFunc 7 0
firstFunc 8 0
firstFunc 9 0
firstFunc 10 0

Understanding a Deadlock in Go

I have the following excerpt from an example given in a programming course, and I am not sure why a deadlock is occurring.
package main
import (
"fmt"
)
var (
Count int = 0
nFunctions int = 2
)
var sema = make(chan int)
func increment(ch chan int, nSteps int) {
for i := 0; i < nSteps; i++ {
<- sema
cnt := Count
Count = cnt + 1
ch <- 1
sema <- 1
}
return
}
func main() {
ch := make(chan int)
sema <- 1
go increment(ch, 1000)
go increment(ch, 1000)
for i := 0; i < nFunctions*1000; i++ {
<-ch
}
fmt.Printf("Count = %d\n", Count)
}
Strangely, the deadlock does not occur when I change the statement, in the main, from sema <- 1 to
go func () {
sema <- 1
}()
Any explanations for this much appreciated. The error message is :
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
Channels block both the sender and the receiver. If you send something, you are blocked until it is received. You could reduce your code even further, all you need is a channel and then write to that channel. Note that you could also use a buffered channel, which allows writes up to the buffer length without blocking. If the buffer is full however, it does still block.

All channels are deadlocked

I'm trying to use a for loop that continuously sends strings to different channels read by different goroutines. However, it gives me the error "all goroutines are asleep - deadlock!" Why is this happening? I searched for some answers, but I couldn't find an answer for this situation.
func main() {
var chans []chan string
for i := 0; i < 3; i++ {
chans = append(chans, make(chan string))
}
for i := 0; i < 3; i++ {
go sendString(chans[i])
}
for str := range chans[0] {
fmt.Print(str)
}
}
func sendString(ch chan string) {
ch <- "a"
ch <- "b"
ch <- "c"
ch <- "d"
}
The errors are here. It prints "abcd", then generates the error, and if I delete the loop for printing, the program does not generate the error.
abcdfatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:18 +0x28d
goroutine 19 [chan send]:
main.sendString(0xc04203c120)
C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:24 +0x42
created by main.main
C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:15 +0x175
goroutine 20 [chan send]:
main.sendString(0xc04203c180)
C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:24 +0x42
created by main.main
C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:15 +0x175
exit status 2
I did the version using WaitGroup, but it seems not correct, and gives me the same error " all goroutines are asleep - deadlock!" where did I do wrong in the code below ?
func main() {
var myWaitGroup sync.WaitGroup
ch := make(chan string)
myWaitGroup.Add(1)
go sendString(ch, &myWaitGroup)
myWaitGroup.Wait()
close(ch)
time.Sleep(1 * time.Second)
}
func sendString(ch chan string, pg *sync.WaitGroup) {
ch <- "a"
ch <- "b"
ch <- "c"
ch <- "d"
defer pg.Done()
}
The second for loop will block until the channel is closed so you need to close it in the sending function. Also, you only read from the first channel so some of the data is lost. Doing this:
func main() {
var chans []chan string
for i := 0; i < 3; i++ {
chans = append(chans, make(chan string))
}
for i := 0; i < 3; i++ {
go sendString(chans[i])
}
for i := 0; i < 3; i++ {
for str := range chans[i] {
fmt.Print(str)
}
}
}
func sendString(ch chan string) {
ch <- "a"
ch <- "b"
ch <- "c"
ch <- "d"
close(ch)
}
Will produce:
abcdabcdabcd
https://play.golang.org/p/7SoDKChnTbz
If you wanted to do this with a single channel as per your comment then you could add a wait group to close the channel once all the go routines are complete:
func main() {
c := make(chan string)
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1)
go func() {
sendString(c)
wg.Done()
}()
}
go func() {
wg.Wait()
close(c)
}()
for str := range c {
fmt.Print(str)
}
}
func sendString(ch chan string) {
ch <- "a"
ch <- "b"
ch <- "c"
ch <- "d"
}
https://play.golang.org/p/E_awt8UBK9v

Golang channel is asleep

I'm new with golang channels and could not underestimate why does program behavior changes if I specify channel buffer size
package main
import (
"fmt"
)
func channels(in <-chan bool, out chan int) {
for {
select {
case _ = <-in:
fmt.Println("Close")
close(out)
return
default:
fmt.Println("Out")
out <- 1
break
}
}
}
func main() {
in := make(chan bool)
// in := make(chan bool, 1)
out := make(chan int)
go channels(in, out)
i := 0
// Loop:
for n := range out {
fmt.Println(n)
i += 1
if i > 10 {
fmt.Println("Send close")
in <- true // Here it is became asleep
return
}
}
fmt.Println("Done")
}
Output is:
Out
Out
1
1
Out
Out
1
1
Out
Out
1
1
Out
Out
1
1
Out
Out
1
1
Out
Out
1
Send close
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/home/user/go-lessons/3/chan_4.go:39 +0x2c3
goroutine 19 [chan send]:
main.channels(0xc820072060, 0xc8200720c0)
/home/user/go-lessons/3/chan_4.go:16 +0x241
created by main.main
/home/user/go-lessons/3/chan_4.go:27 +0x97
exit status 2
If I replace in := make(chan bool) with in := make(chan bool, 1) It works properly. Why does it happen?
This is because the main goroutine is stuck writing to in
in <- true
and the other goroutine is stuck writing to out
out <- 1
If you make the write to out a case aswell it should work:
for {
select {
case <-in:
fmt.Println("Close")
close(out)
return
case out <- 1:
fmt.Println("Out")
break
}
}

Go select statement

A short program about select statement for channels.
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case s := <-quit:
fmt.Println("quit =",s)
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 9
}()
fibonacci(c, quit)
}
The result of the code above:
0
1
1
2
3
5
8
13
21
34
quit = 9
It worked fine. But after I changed (in func fibonacci)
case s := <-quit:
fmt.Println("quit =",s)
to
case <-quit:
fmt.Println(<-quit)
an fatal error occurred:
0
1
1
2
3
5
8
13
21
34
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.fibonacci(0x18348040, 0x18348080)
/tmp/compile42.go:12 +0xf9
main.main()
/tmp/compile42.go:27 +0x11c
Where does the error come from?
In second case you are getting the value form the channel two times. Every time you do something like <-channel you pop one value out of channel.
Hence program is waiting indefinitely on line
fmt.Println(<-quit)
but fortunately go is intelligent enough to detect this situation and panic with error "all goroutines are asleep - deadlock!"
The line
fmt.Println(<-quit)
is waiting for another value on the channel, which will never come, according to the code you have.
You have to keep in mind the line before in the select:
case s := <-quit
has already removed the quit value from the channel.
Thus it will never complete.

Resources