Why does this tree walking function deadlock? - go

I am going through the Tour of Go to refresh my memory, and am stumbling on the Equivalent Binary Trees exercise. I have written some code to traverse a binary tree that looks like it should work.
package main
import (
"golang.org/x/tour/tree"
"fmt"
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t == nil {
return
}
ch <- t.Value
Walk(t.Left, ch)
Walk(t.Right, ch)
}
func main() {
ch := make(chan int, 10)
go Walk(tree.New(3), ch)
for v := range ch {
fmt.Printf("%q", v)
}
}
When I run the above code I'm getting the following error:
'\x1e''\x0f''\t''\x03''\x06''\f''\x15''\x12''\x1b''\x18'fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/Users/james/src/local/go-sandbox/main.go:22 +0x115
Process finished with exit code 2
I am wondering why it is deadlocking? It looks like it does print out some garbage before this happens.

You must close the channel so range loop over it will terminate:
func main() {
ch := make(chan int, 10)
go func() {
Walk(tree.New(3), ch)
close(ch)
}()
for v := range ch {
fmt.Printf("%q", v)
}
}

The range loop will read until ch is closed, but you never close it, so you end up in state where the main goroutine is asleep waiting to receive on ch, but no other goroutines exist to send to it — "all" one of your goroutines are asleep.
I'd simply wrap the Walk call in main like this:
go func() {
Walk(tree.New(3), ch)
close(ch)
}()
See the Tour of Go entry a few earlier than the one you linked to for a refresher on Range and Close.

Related

Go routine with channel deadlock

I just started to learn Go so please bear with me, I've tried to play around with Go routines and channels but are getting a deadlock somehow.
Here's the example
package main
import (
"fmt"
"sync"
)
func main() {
total := 2
var wg sync.WaitGroup
wg.Add(total)
ch := make(chan int)
for idx := 0; idx < total; idx++ {
fmt.Printf("Processing idx %d\n", idx)
go func(idx int) {
defer wg.Done()
ch <- idx
}(idx)
}
for val := range ch {
fmt.Println(val)
}
fmt.Println("Wait")
wg.Wait()
}
which throws the error
Processing idx 0
Processing idx 1
1
0
fatal error: all goroutines are asleep - deadlock!
range ch reads from the channel until it is closed.
How many times do you call close(ch)? When will the for val := range ch loop terminate?
When should you close the channel? You have a lot of options here, but one way to do it is to add another goroutine:
go func() {
wg.Wait()
close(ch)
}()
e.g., after spinning off all routines that will write-to-channel-then-call-wg.Done(), so that the channel is closed once all the writers are done writing. (You can run this goroutine as soon as you've increased the wg count to account for all writers.)

Reading outputs from two channels in a forever loop

I am working on the tree exercise of tour.golang. I have tried to implement the same function as written below.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1);
go Walk(t2, ch2);
for c := range ch1 {
d := <- ch2
if c-d !=0 {
return false
}
}
return true
}
Using the forever loop, I would like to compare if an output from ch1 is different from that of ch2. But the following is throwing this error:
fatal error: all goroutines are asleep - deadlock!
live version
You are seeing a deadlock for a very simple reason: you are ranging over ch1, but never closing it, so the for loop never terminates.
You could fix this by manually iterating over each tree only a certain number of times like your 0..10 loop in main():
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for i := 0; i < 10; i++ {
c := <-ch1
d := <-ch2
if c-d != 0 {
return false
}
}
return true
}
Playground
Alternatively, you can alter the signature of Walk to accept a waitgroup argument that is incremented by the caller of Walk and decremented when each Walk returns along with a goroutine to close the channel once you're done walking:
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int, wg *sync.WaitGroup) {
defer wg.Done()
if t.Left != nil {
wg.Add(1)
Walk(t.Left, ch, wg)
}
ch <- t.Value
if t.Right != nil {
wg.Add(1)
Walk(t.Right, ch, wg)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
var wg1 sync.WaitGroup
wg1.Add(1)
go Walk(t1, ch1, &wg1)
go func() {
wg1.Wait()
close(ch1)
}()
var wg2 sync.WaitGroup
wg2.Add(1)
go Walk(t2, ch2, &wg2)
go func() {
// not strictly necessary, since we're not ranging over ch2, but here for completeness
wg2.Wait()
close(ch2)
}()
for c := range ch1 {
d := <-ch2
if c-d != 0 {
return false
}
}
return true
}
Playground
You should close the channel after walking the tree to terminate the range loop in case the trees are equal (to be aware of: Same returns true when the infix traversal of the trees is equal, their structure is not required to be equal).
func WalkTreeAndThenCloseChannel(t *tree.Tree, ch chan int) {
Walk(t, ch)
close(ch)
}
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go WalkTreeAndThenCloseChannel(t1, ch1);
go WalkTreeAndThenCloseChannel(t2, ch2);
Note: You should check if the second channel has been closed in case the trees have a different number of items and a difference is not found ("thread starvation" would be a more appropriate term here than "deadlock").
There is a problem here you are not sending a value to a channel for right subtree in walk function. But receiving it on other side that's why deadlock error. Because you are receiving a value from channel in case of right subtree which is never sent.

Go: transformed channel

Let's say I have an int channel in Go:
theint := make(chan int)
I want to wrap this channel in a new channel called incremented
incremented := make(chan int)
Such that:
go func() { theint <- 1 }
<- incremented // 2
appended can be assumed to be the only one that reads from the int.
It will work if a run a goroutine in the background
go func() {
for num := range theint {
incremented <- num + 1
}
}
However, I prefer to do it without a goroutine since I can't control it in my context.
Is there a simpler way to do it?
One thing that came to mind is python's yield:
for num in theint:
yield num + 1
Is something like this possible in go?
Generator pattern
What you are trying to implement is generator pattern. To use channels and goroutines for implementation of this pattern is totally common practice.
However, I prefer to do it without a goroutine since I can't control it in my context.
I believe the problem is deadlock
fatal error: all goroutines are asleep - deadlock!
To avoid deadlocks and orphaned (not closed) channels use sync.WaitGroup. This is an idiomatic way to control goroutines.
Playground
package main
import (
"fmt"
"sync"
)
func incGenerator(n []int) chan int {
ch := make(chan int)
var wg sync.WaitGroup
wg.Add(len(n))
for _, i := range n {
incremented := i + 1
go func() {
wg.Done()
ch <- incremented
}()
}
go func() {
wg.Wait()
close(ch)
}()
return ch
}
func main() {
n := []int{1, 2, 3, 4, 5}
for x := range incGenerator(n) {
fmt.Println(x)
}
}
One thing you can also consider is having a select on the int channel and an exit channel - in an infinite for loop. You can choose a variable increment value too. Please see code below:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var accum int //accumulator of incremented values
var wg sync.WaitGroup
c1 := make(chan int)
exChan := make(chan bool)
wg.Add(1)
go func() {
time.Sleep(time.Second * 1)
c1 <- 1
wg.Done()
}()
wg.Add(1)
go func() {
time.Sleep(time.Second * 2)
c1 <- 2
wg.Done()
}()
wg.Add(1)
go func() {
time.Sleep(time.Second * 2)
c1 <- 5
wg.Done()
}()
go func() {
wg.Wait()
close(exChan)
}()
for {
var done bool
select {
case incBy := <-c1: //Increment by value in channel
accum += incBy
fmt.Println("Received value to increment:", incBy, "; Accumulated value is", accum)
case d := <-exChan:
done = !(d)
}
if done == true {
break
}
}
fmt.Println("Final accumulated value is", accum)
}
Playground: https://play.golang.org/p/HmdRmMCN7U
Exit channel not needed, if we are having non-zero increments always. I like #I159 's approach too!
Anyways, hope this helps.

Why happen here a deadlock

I am trying to understand, how golang channel works. I read a book about the go language and found the following example.
package main
import (
"fmt"
)
// Send the sequence 2, 3, 4, ... to returned channel
func generate() chan int {
ch := make(chan int)
go func() {
for i := 2; i <= 100 ; i++ {
ch <- i
}
}()
return ch
}
// Filter out input values divisible by 'prime', send rest to returned channel
func filter(in chan int, prime int) chan int {
out := make(chan int)
go func() {
for {
if i := <-in; i%prime != 0 {
out <- i
}
}
}()
return out
}
func sieve() chan int {
out := make(chan int)
go func() {
ch := generate()
for {
prime := <-ch
ch = filter(ch, prime)
out <- prime
}
}()
return out
}
func main() {
primes := sieve()
for {
fmt.Println(<-primes)
}
}
When I run this programm, I've got a deadlock, but when I change the generate function to
// Send the sequence 2, 3, 4, ... to returned channel
func generate() chan int {
ch := make(chan int)
go func() {
for i := 2; ; i++ {
ch <- i
}
}()
return ch
}
Then the programm will run the infinite loop, but not deadlock. Why do I get deadlock, when I remove the condition in for loop?
What do you mean with blocking principle?
You can see it illustrated in the blog post "The Nature Of Channels In Go "
for an unbuffered channel:
(Illustration from blog post "The Nature Of Channels In Go ", written by William Kennedy, Feb. 2014)
Unbuffered channels have no capacity and therefore require both goroutines to be ready to make any exchange.
When a goroutine attempts to write a resource to an unbuffered channel and there is no goroutine waiting to receive the resource, the channel will lock the goroutine and make it wait.
When a goroutine attempts to read from an unbuffered channel, and there is no goroutine waiting to send a resource, the channel will lock the goroutine and make it wait.
That is what happens in your case with your reader:
func main() {
primes := sieve()
for {
fmt.Println(<-primes)
}
}
since primes is never closed, main remains blocked.
It (main) is in step 3:
in step 3, the goroutine on the right places his hand into the channel or performs a read.
That goroutine is also locked in the channel until the exchange is complete.
The sender never calls close(primes).
Let's consider a simpler example:
func generate() chan int {
ch := make(chan int)
go func() {
for i := 2; /*i < 100*/; i++ {
ch <- i
}
}()
return ch
}
func main() {
for i := range generate() {
fmt.Println(i)
}
}
With the condition i < 100 uncommented, the goroutine spawned by generate stops after sending 98 numbers. However, it does not close the channel, so main has no way of knowing that no more numbers are going to be sent, and it just keeps blocking on the channel. Since main is now the only goroutine still in existence (the other one has returned), and it's blocking, you have a deadlock.

How do I catch the exception of a channel deadlocking?

I am learning Go and am working on this lesson from the GoTours. Here's what I have so far.
package main
import (
"fmt"
"code.google.com/p/go-tour/tree"
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t != nil {
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right, ch)
}
}
func main() {
var ch chan int = make(chan int)
go Walk(tree.New(1), ch)
for c := range ch {
fmt.Printf("%d ", c)
}
}
As you see, I try to test out my Walk function by printing out the values I wrote into a channel. However, I get the following error.
1 2 3 4 5 6 7 8 9 10 throw: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
main.go:25 +0x85
goroutine 2 [syscall]:
created by runtime.main
/usr/local/go/src/pkg/runtime/proc.c:221
exit status 2
This error should be expected I think because I never close the channel. However, is there a way I could "catch" this deadlock error and deal with it programmatically?
Deadlock is similar to a nil pointer deference in that is represents a BUG in your program. This class of error is usually not recoverable for this reason.
As lbonn mentioned, the problem here is you need to "close(myChan)" your channel. If you do not do this the for-range loop, that the loop will wait for the next element forever.
You can try something like this:
func main() {
var ch chan int = make(chan int)
go func() {
Walk(tree.New(1), ch)
close(ch)
}()
for c := range ch {
fmt.Printf("%d ", c)
}
}
If you want to traverse the tree in parallel you will need to make further changes:
package main
import (
"code.google.com/p/go-tour/tree"
"fmt"
"sync"
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int, done *sync.WaitGroup) {
if t != nil {
done.Add(2)
go Walk(t.Left, ch, done) //look at each branch in parallel
go Walk(t.Right, ch, done)
ch <- t.Value
}
done.Done()
}
func main() {
var ch chan int = make(chan int, 64) //note the buffer size
go func() {
done := new(sync.WaitGroup)
done.Add(1)
Walk(tree.New(1), ch, done)
done.Wait()
close(ch)
}()
for c := range ch {
fmt.Printf("%d ", c)
}
}
This deadlocks because, the range construct iterates until the channel is closed.
http://golang.org/ref/spec#For_statements
Here, you need to either close the channel when the tree is fully explored or use another construct.
For this example, you know that the trees are of size 10, so you can simply do a for loop from 1 to 10 and read from the channel once at each iteration.
No, you cannot recover from a deadlock.
The channel deadlock error is:
fatal error: all goroutines are asleep - deadlock!
channel deadlock is not a panic error, it's a fatal error, see https://golang.org/pkg/log/#Fatal
Fatal is equivalent to Print() followed by a call to os.Exit(1).
As you can see, Fatal will call os.Exit(1) at last, so it's totally different with panic, and that's why it can't be recover
I came up with this solution, It basically uses 2 channels and concludes the trees are same if both the channels are closed.
package main
import "golang.org/x/tour/tree"
import "fmt"
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t == nil {
return
}
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right, ch)
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
tc1 := make(chan int)
tc2 := make(chan int)
go func() {
Walk(t1, tc1)
close(tc1)
}()
go func() {
Walk(t2, tc2)
close(tc2)
}()
for {
x1, y1 := <-tc1;
x2, y2 := <-tc2;
if x1 != x2 {
return false
}
if !y1 || !y2 {
return true
}
}
}
func main() {
t1, t2 := tree.New(123), tree.New(1)
fmt.Println(Same(t1, t2))
}
I'm following go-tour guide and only used resources taught so far (Unlike using sync package in the above solution.)

Resources