我正在进行tour.golang的树木练习。我试图实现与下面写的相同的功能。
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
}
使用forever循环,我想比较ch1
的输出是否与ch2
的输出不同。但是以下是抛出这个错误:
致命错误:所有goroutine都睡着了 - 死锁!
答案 0 :(得分:3)
你应该在遍历树之后关闭通道以终止范围循环,以防树木相等(要注意:Same
当树的中缀遍历相等时返回true,它们的结构不是要求是平等的。)
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);
注意:您应该检查第二个频道是否已经关闭,以防树木的项目数量不同而且找不到差异(&#34;线程饥饿&#34;这里的术语比&更合适#34;死锁&#34;。)
答案 1 :(得分:3)
您看到一个死锁的原因非常简单:您的范围超过ch1
,但从未关闭它,因此for循环永远不会终止。
您可以通过在main()
中手动迭代每个树只有一些次数来修复此问题,例如0..10循环:
// 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
}
或者,您可以更改Walk的签名以接受由Walk的调用者递增的waitgroup参数,并在每次Walk返回时递减,并且在执行步行后返回goroutine以关闭通道:
// 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
}
答案 2 :(得分:-1)
这里有一个问题,你没有在walk函数中为右子树的通道发送值。但是在另一边接收它就是为什么死锁错误。因为在从未发送的右子树的情况下,您从通道接收值。