8

Could someone explain, why if the channel is buffered the program doesn't exit with a fatal_error?

Unbuffered channel

package main

func main() {
    c := make(chan int)
    c <- 3
}

fatal error: all goroutines are asleep - deadlock!

Buffered channel

package main

func main() {
    c := make(chan int, 1)
    c <- 3
}

[no output]

Program exited.

Thank you!

Eran Chetzroni
  • 1,046
  • 2
  • 14
  • 27
  • I think that is because the difference between buffered and unbuffered channels. In buffered channels the sender waits until the receiver (itself in this case) gets the data. But I'm not sure.. – accurate respondetur Jan 11 '14 at 21:16
  • 2
    possible duplicate of [How does make(chan bool) behave differently from make(chan bool, 1)?](http://stackoverflow.com/questions/20041392/how-does-makechan-bool-behave-differently-from-makechan-bool-1) – Matt Jan 12 '14 at 01:46

3 Answers3

11

Writing to a buffered channel doesn't block if there is room in the buffer.

If you try to put two items in the channel with a buffer size of one, you get the same error:

package main

func main() {
    c := make(chan int, 1)
    c <- 3
    c <- 4
}

gives you:

fatal error: all goroutines are asleep - deadlock!
Sean
  • 1,785
  • 10
  • 15
4

It's a core concept of Go's channels (or other CSP implementations such as Clojure's core.async library) that they are blocking. In general, as you already mentioned, there're two types of channels:

  • buffered which block if the buffer is full.
  • unbuffered which block if there's no "rendezvous", i.e. there must be someone who puts (c <-) to and someone who takes (<- c) from the channel.

In your particular case the Go runtime is smart enough to detect that there's no one who will ever take 3 from channel c. Hence, it's a deadlock and (thankfully) an error is thrown.

What you typically do when you're working with channels is using goroutines (checkout this introduction) which spawn a lightweight thread—managed by the Go runtime—to execute the body concurrently:

c := make(chan int)

go func() { c <- 3 }() // Create a new gorountine that puts 3 to the channel

fmt.Println(<- c) // Take 3 from the channel and print it in the main thread
beatngu13
  • 7,201
  • 6
  • 37
  • 66
2

Thanks @Matt

I found the answer in this post How does make(chan bool) behave differently from make(chan bool, 1)? :

Actually that's the reason why your problem is generated. Un-buffered channels are only writable when there's someone blocking to read from it, which means you shall have some coroutines to work with -- instead of this single one.

Community
  • 1
  • 1