case1
package main
func main() {
dogChan := make(chan int)
dogChan <- 1
}
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/Users/xuzhongwei/Source/awesomeProject/main.go:5 +0x50
case2
package main
func main() {
dogChan := make(chan int)
go func(ch chan int) {
}(dogChan)
dogChan <- 1
}
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/Users/xuzhongwei/Source/awesomeProject/main.go:9 +0x72
case3
package main
func main() {
dogChan := make(chan int)
go func(ch chan int) {
<- ch
}(dogChan)
dogChan <- 1
}
case4
package main
func main() {
dogChan := make(chan int)
go func(ch chan int) {
<- ch
}(dogChan)
dogChan <- 1
dogChan <- 2
}
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/Users/xuzhongwei/Source/awesomeProject/main.go:10 +0x90
case5
package main
func main() {
dogChan := make(chan int)
go func(ch chan int) {
for {
select {
case <- ch:
}
}
}(dogChan)
dogChan <- 1
dogChan <- 2
dogChan <- 3
dogChan <- 4
dogChan <- 5
}
Could anyone tell me why case1, case2 got errors while case3 is ok?
In case1 my guess is that dogChan is not used in goroutine so it is treated to be closed.
In case2 my guess is that although dogChan is passed in goroutine but it is not used in goroutine so it is treated to be closed
Could anyone tell me why case4 got errors while case5 is ok?
Why do you think thats happening in case1 and case2? The channels are meant to behave as a synchronisation primitive between a sender and receiver. You have a sender sending on a channel, dogChan but none is receiving on it.
Without a receiving goroutine or a receive operation on a goroutine, the sender simply blocks (being a unbuffered channel)
Same problem on case4, you have two sends on the channel, but a single receive on the goroutine. The dogChan <- 2 will block forever. In case5, if your intention was to read from the channel, simply use a range loop to iterate over the successive values sent over it.
Golang expects program to read message(s) placed into channel.
Consumer (reader) needs to drain (read) all messages from channel, either using simple for-read, or for-select. Channel send and receive both block until sender and receiver are ready.
case1, case2 = send one message to channel, block awaiting reader, read zero messages
case4 = send one message to channel, block awaiting reader, reader does not consume (read) message
case3 = send one message to channel, consume one message from channel, sender blocks awaiting reader
case5 = send five messages to channel, consume all (five) messages, each send blocks until reader receives
// for range over channel
for msg := range ch {
// process msg
}
// for select
done := false
for !done {
select {
case msg := <-ch: {
// process msg
}
case ch == nil: {
done = true
}
}
}
// producer should close channel
close(ch)
Note:
channel can be buffered, specify a channel (queue) size
channel size default = 1 (unbuffered), writer blocks when channel full
Related
// By default channels are _unbuffered_, meaning that they
// will only accept sends (`chan <-`) if there is a
// corresponding receive (`<- chan`) ready to receive the
// sent value. _Buffered channels_ accept a limited
// number of values without a corresponding receiver for
// those values.
package main
import "fmt"
func main() {
// Here we `make` a channel of strings buffering up to
// 2 values.
messages := make(chan string, 2)
// Because this channel is buffered, we can send these
// values into the channel without a corresponding
// concurrent receive.
messages <- "buffered"
messages <- "channel"
messages <- "channel1" //I added this.
// Later we can receive these two values as usual.
fmt.Println(<-messages)
fmt.Println(<-messages)
}
Error it throws:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/tmp/sandbox795158698/prog.go:23 +0x8d
Questions:
Can't we send more values than buffer size?
Why the error says
"all goroutines are asleep - deadlock!" when there are no goroutines
here in the code?
Why is it this a deadlock? Please explain?
PlayGroundLink
An attempt to write to a full channel will block until some other goroutine reads from it. In your program, there are no other goroutines. So when you write to the full channel, the main goroutine blocks, and since there are no other goroutines, there is no chance that the main goroutine ever can progress. That is a deadlock.
Adding to the above answer: https://stackoverflow.com/a/61512364/4106031
package main
import (
"fmt"
"github.com/practo/klog/v2"
"os"
"os/signal"
"syscall"
"time"
)
func producer(msgBuf chan<- string) {
for i := 0; ; i++ {
fmt.Printf("sent: %d\n", i)
msgBuf <- fmt.Sprintf("%d", i)
time.Sleep(1 * time.Second)
}
}
func process(msgBuf <-chan string) {
time.Sleep(10 * time.Second)
for {
select {
case msg := <-msgBuf:
fmt.Printf("processing: %v\n", msg)
time.Sleep(10 * time.Second)
fmt.Printf("processed: %v\n", msg)
}
}
}
func main() {
msgBuf := make(chan string, 2)
go producer(msgBuf)
go process(msgBuf)
sigterm := make(chan os.Signal, 1)
signal.Notify(sigterm, syscall.SIGINT, syscall.SIGTERM)
for {
select {
default:
case <-sigterm:
klog.Info("SIGTERM signal received")
os.Exit(1)
}
}
}
This won't cause the deadlock as you are running them in different go routines.
I am trying to understand the difference between calling goroutine with/without anonymous function.
When I try below code with anonymous function it works.
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
go func() {
fmt.Println(<-ch)
}()
go send(1, ch)
time.Sleep(100 * time.Millisecond)
}
Below code without a anonymous function fails with deadlock.
go fmt.Println(<-ch) //fatal error: all goroutines are asleep - deadlock!
The code is available here
The Go Programming Language Specification
Receive operator
For an operand ch of channel type, the value of the receive operation
<-ch is the value received from the channel ch. The channel direction
must permit receive operations, and the type of the receive operation
is the element type of the channel. The expression blocks until a
value is available.
For example,
package main
import "fmt"
func main() {
ch := make(chan int)
go fmt.Println(<-ch)
ch <- 1
}
Playground: https://play.golang.org/p/K3_V92NRWvY
Output:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
// At prog.go: line 7: (<-ch)
fmt.Println(<-ch) evaluates its arguments, a receive on ch. There is no send pending for ch. fmt.Println(<-ch) blocks until a value is available, which never happens, it never gets to ch <- 1.
It is equivalent to:
package main
import "fmt"
func main() {
ch := make(chan int)
arg := <-ch
go fmt.Println(arg)
ch <- 1
}
Playground: https://play.golang.org/p/1wyVTe-8tyB
Output:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
// At prog.go: line 7: arg := <-ch
I have a snippet of code that I am trying to understand based on how I put the close call and the location
func main() {
ch := make(chan int, 2)
go func(ch chan int) {
for i := 1; i <= 5; i++ {
ch <- i
fmt.Println("Func goroutine sends data: ", i)
}
//Pos1 - Works perfectly
//close(ch)
}(ch)
fmt.Println("Main goroutine sleeps 2 seconds")
time.Sleep(time.Second * 2)
fmt.Println("Main goroutine begins receiving data")
//Pos2 - Puts in only 2 ints 1 and 2 and then prints only that
//close(ch)
for d := range ch {
fmt.Println("Main goroutine received data:", d)
}
//Pos3 - Throws fatal error
close(ch)
}
I have been trying to understand and read blogs on this but not able to understand somethings still
When I place the close at Pos1, it works fine. But I am not sure why
it works. The buffer cannot hold more than 2 elements at any given
time, so when 2 elements are written, the loop will block until the
main routing does a read. But I thought to do a range over a
buffered channel, the range function has to know beforehand how many
elements to iterate over and for that channel must be closed. Why
does close work at this position?
When I put it as position 2, it prints only 2 elements which kind of makes sense but why is the for loop not throwing an exception when it is trying to write more elements to the channel that is closed?
When I close at Pos3, I get an exception fatal error: all goroutines are asleep - deadlock! though all 5 ints are printed. Why is that?
But I thought to do a range over a buffered channel, the range function has to know beforehand how many elements to iterate over and for that channel must be closed.
That assumption is wrong and the root of all misunderstandings.
The behavior of ranging over a channel is described in the Go Spec: https://golang.org/ref/spec#For_statements
For channels, the iteration values produced are the successive values sent on the channel until the channel is closed. If the channel is nil, the range expression blocks forever.
The channel does not need to be closed when the for statement is evaluated and the statement does not need to know number of elements.
So, in your code, when you put close in Pos1, it is indeed the right way to do it. When you put it in Pos3, the for loop waits the channel to be closed, which can only happen after the for loop itself, so it is a deadlock.
Putting close in Pos2 is buggy and the behavior is a little tricky. It is possible to raise an error, yet it is possible to just output two numbers. This is because when the channel is closed before the for loop, the loop can run without block and then main() returns. And when main() returns, the Go program ends. Whether it raises an error solely depends on if the scheduler switch to goroutine between the process, which is not guaranteed.
Modifying the code snippets with some peppered print statements to add on to the excellent answer by #leaf bebop, to clarify what's happening.
Pos 2, but make main wait a bit
func main() {
ch := make(chan int, 2)
go func(ch chan int) {
for i := 1; i <= 5; i++ {
ch <- i
fmt.Println("Func goroutine sends data: ", i)
}
fmt.Println("goR work is done")
}(ch)
fmt.Println("Main goroutine sleeps 2 seconds")
time.Sleep(time.Second * 2)
fmt.Println("Main goroutine begins receiving data")
close(ch)
for d := range ch {
fmt.Println("Main goroutine received data:", d)
}
fmt.Println("Main waiting, will the other goR panic?")
time.Sleep(time.Second * 10)
}
Main goroutine sleeps 2 seconds
Func goroutine sends data: 1
Func goroutine sends data: 2
Main goroutine begins receiving data
Main goroutine received data: 1
panic: send on closed channel
goroutine 6 [running]:
main.main.func1(0x0?)
/tmp/sandbox3746599466/prog.go:15 +0x3b
created by main.main
/tmp/sandbox3746599466/prog.go:13 +0x85
Program exited.
So, given enough time (main routine didn't exit), the scheduler went back to the go routine, where we wrote to a closed (closed by main) channel - Panic!
Pos 2, but only send 2 values, i.e not writing to a closed channel
func main() {
ch := make(chan int, 2)
go func(ch chan int) {
// Send only 2 values
for i := 1; i <= 2; i++ {
ch <- i
fmt.Println("Func goroutine sends data: ", i)
}
fmt.Println("goR work is done")
}(ch)
fmt.Println("Main goroutine sleeps 2 seconds")
time.Sleep(time.Second * 2)
fmt.Println("Main goroutine begins receiving data")
close(ch)
for d := range ch {
fmt.Println("Main goroutine received data:", d)
}
fmt.Println("Main waiting, will the other goR panic?")
time.Sleep(time.Second * 10)
fmt.Println("Main exiting")
}
Main goroutine sleeps 2 seconds
Func goroutine sends data: 1
Func goroutine sends data: 2
goR work is done
Main goroutine begins receiving data
Main goroutine received data: 1
Main goroutine received data: 2
Main waiting, will the other goR panic?
Main exiting
Program exited.
No panic, no spinning for ever. Main routine just exits.
Pos 3, check if main got unblocked?
func main() {
ch := make(chan int, 2)
go func(ch chan int) {
for i := 1; i <= 5; i++ {
ch <- i
fmt.Println("Func goroutine sends data: ", i)
}
fmt.Println("Routine done with work")
}(ch)
fmt.Println("Main goroutine sleeps 2 seconds")
time.Sleep(time.Second * 2)
fmt.Println("Main goroutine begins receiving data")
for d := range ch {
fmt.Println("Main goroutine received data:", d)
}
fmt.Println("Have I closed this channel?")
close(ch)
fmt.Println("I have")
}
Main goroutine sleeps 2 seconds
Func goroutine sends data: 1
Func goroutine sends data: 2
Main goroutine begins receiving data
Main goroutine received data: 1
Main goroutine received data: 2
Main goroutine received data: 3
Func goroutine sends data: 3
Func goroutine sends data: 4
Func goroutine sends data: 5
Routine done with work
Main goroutine received data: 4
Main goroutine received data: 5
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/tmp/sandbox3301646152/prog.go:26 +0x194
Program exited.
Main never got even to close the channel, it was blocked in the range loop. It'll stay here forever, until it gets a value, or someone closes the channel. We don't have any other routine to do that, so deadlock.
Like here I created a go playground sample: sGgxEh40ev, but cannot get it work.
quit := make(chan bool)
res := make(chan int)
go func() {
idx := 0
for {
select {
case <-quit:
fmt.Println("Detected quit signal!")
return
default:
fmt.Println("goroutine is doing stuff..")
res <- idx
idx++
}
}
}()
for r := range res {
if r == 6 {
quit <- true
}
fmt.Println("I received: ", r)
}
Output:
goroutine is doing stuff..
goroutine is doing stuff..
I received: 0
I received: 1
goroutine is doing stuff..
goroutine is doing stuff..
I received: 2
I received: 3
goroutine is doing stuff..
goroutine is doing stuff..
I received: 4
I received: 5
goroutine is doing stuff..
goroutine is doing stuff..
fatal error: all goroutines are asleep - deadlock!
Is this possible? Where am I wrong
The problem is that in the goroutine you use a select to check if it should abort, but you use the default branch to do the work otherwise.
The default branch is executed if no communications (listed in case branches) can proceed. So in each iteration quit channel is checked, but if it cannot be received from (no need to quit yet), default branch is executed, which unconditionally tries to send a value on res. Now if the main goroutine is not ready to receive from it, this will be a deadlock. And this is exactly what happens when the sent value is 6, because then the main goroutine tries to send a value on quit, but if the worker goroutine is in the default branch trying to send on res, then both goroutines try to send a value, and none is trying to receive! Both channels are unbuffered, so this is a deadlock.
In the worker goroutine you must send the value on res using a proper case branch, and not in the default branch:
select {
case <-quit:
fmt.Println("Detected quit signal!")
return
case res <- idx:
fmt.Println("goroutine is doing stuff..")
idx++
}
And in the main goroutine you must break out from the for loop so the main goroutine can end and so the program can end as well:
if r == 6 {
quit <- true
break
}
Output this time (try it on the Go Playground):
goroutine is doing stuff..
I received: 0
I received: 1
goroutine is doing stuff..
goroutine is doing stuff..
I received: 2
I received: 3
goroutine is doing stuff..
goroutine is doing stuff..
I received: 4
I received: 5
goroutine is doing stuff..
goroutine is doing stuff..
The fundamental issue is that producer must always check in between sending values if the consumer (main in your case) has decided to quit reading (in your code this is optional). What's happening is even before the value of quit is sent (and received), the producer goes ahead and sends the next value on res which the consumer never is able to read - the consumer is in fact trying to send the value on the quit channel expecting the producer to read. Added a debug statement which can help you understand : https://play.golang.org/p/mP_4VYrkZZ, - producer is trying to send 7 on res and blocking, and then consumer trying to send value on quit and blocking. Deadlock!
One possible solution is as follows (using a Waitgroup is optional, needed only if you need a clean exit from producer side before return):
package main
import (
"fmt"
"sync"
)
func main() {
//WaitGroup is needed only if need a clean exit for producer
//that is the producer should have exited before consumer (main)
//exits - the code works even without the WaitGroup
var wg sync.WaitGroup
quit := make(chan bool)
res := make(chan int)
go func() {
idx := 0
for {
fmt.Println("goroutine is doing stuff..", idx)
res <- idx
idx++
if <-quit {
fmt.Println("Producer quitting..")
wg.Done()
return
}
//select {
//case <-quit:
//fmt.Println("Detected quit signal!")
//time.Sleep(1000 * time.Millisecond)
// return
//default:
//fmt.Println("goroutine is doing stuff..", idx)
//res <- idx
//idx++
//}
}
}()
wg.Add(1)
for r := range res {
if r == 6 {
fmt.Println("Consumer exit condition met: ", r)
quit <- true
break
}
quit <- false
fmt.Println("I received: ", r)
}
wg.Wait()
}
Output:
goroutine is doing stuff.. 0
I received: 0
goroutine is doing stuff.. 1
I received: 1
goroutine is doing stuff.. 2
I received: 2
goroutine is doing stuff.. 3
I received: 3
goroutine is doing stuff.. 4
I received: 4
goroutine is doing stuff.. 5
I received: 5
goroutine is doing stuff.. 6
Consumer exit condition met: 6
Producer quitting..
On playground : https://play.golang.org/p/N8WSPvnqqM
As #icza's answer is pretty clean, which #Ravi's goes to the synchronised way.
But coz I don't want to spend that much effort to restructure the code, and also I don't want to go to the synchronised way, so eventually went to the defer panic recover flow control, as below:
func test(ch chan<- int, data []byte) {
defer func() {
recover()
}()
defer close(ch)
// do your logic as normal ...
// send back your res as normal `ch <- res`
}
// Then in the caller goroutine
ch := make(chan int)
data := []byte{1, 2, 3}
go test(ch, data)
for res := range ch {
// When you want to terminate the test goroutine:
// deliberately close the channel
//
// `go -race` will report potential race condition, but it is fine
//
// then test goroutine will be panic due to try sending on the closed channel,
// then recover, then quit, perfect :)
close(ch)
break
}
any potential risk with this approach?
Here is an example:
func main() {
c := make(chan int)
i := 0
go goroutine(c)
c <- i
time.Sleep(10 * time.Second)
}
func goroutine(c chan int) {
for {
num := <- c
fmt.Println(num)
num++
time.Sleep(1 * time.Second)
c <- num
}
}
What I'm trying to do inside of goroutine is to receive number from channel, print it, increment and after one second send it back to the channel. After this I want to repeat the action.
But as a result, operation is only done once.
Output:
0
Am I doing something wrong?
By default the goroutine communication is synchronous and unbuffered: sends do not complete until there is a receiver to accept the value. There must be a receiver ready to receive data from the channel and then the sender can hand it over directly to the receiver.
So channel send/receive operations block until the other side is ready:
1. A send operation on a channel blocks until a receiver is available for the same channel: if there’s no recipient for the value on ch, no other value can be put in the channel. And the other way around: no new value can be sent in ch when the channel is not empty! So the send operation will wait until ch becomes available again.
2. A receive operation for a channel blocks until a sender is available for the same channel: if there is no value in the channel, the receiver blocks.
This is illustrated in the below example:
package main
import "fmt"
func main() {
ch1 := make(chan int)
go pump(ch1) // pump hangs
fmt.Println(<-ch1) // prints only 0
}
func pump(ch chan int) {
for i:= 0; ; i++ {
ch <- i
}
}
Because there is no receiver the goroutine hangs and print only the first number.
To workaround this we need to define a new goroutine which reads from the channel in an infinite loop.
func receive(ch chan int) {
for {
fmt.Println(<- ch)
}
}
Then in main():
func main() {
ch := make(chan int)
go pump(ch)
go receive(ch)
}
Go Playground
You create an unbuffered channel c with
c := make(chan int)
On unbuffered channels, operations are symmentrical, i.e. every send on a channel needs exactly one receive, every receive needs exactly one send. You send your i into the channel, the goroutine receives it into num. After that, the goroutine sends the incremented num into the channel, but nobody is there to receive it.
In short: The statement
c <- num
will block.
You could use a 1-buffered channel, that should work.
There is another problem with your code that you solved by waiting ten seconds in main: You don't know when your goroutine finishes. Typically, a sync.WaitGroup is used in these situations. But: Your goroutine does not finish. It's idiomatic to introduce a chan struct{} that you close in your main goroutine after a while and select over both channels in the worker goroutine.
You use unbuffered channel, so your goroutine hang on c <- num
You should use buffered channel, like this: c := make(chan int, 1)
Try it on the Go playground