通道死锁

huangapple go评论94阅读模式
英文:

Channels Deadlock

问题

我正在使用Go语言和通道构建一个异步B树,但是我遇到了错误fatal error: all goroutines are asleep - deadlock!。我不知道为什么会出现这个错误,因为我正在使用带有缓冲通道的for循环从通道中获取值。

type Obj interface {
	Compare(node Obj) int
}

type Tree struct {
	Item        Obj
	Right, Left *Tree
	height      int16
}

func NewTree() *Tree {
	return &Tree{Item: nil, Right: nil, Left: nil, height: 0}
}

func InOrder(t *Tree, chTree chan Obj) {
	if t != nil {
		InOrder(t.Left, chTree)
		chTree <- t.Item
		InOrder(t.Right, chTree)
	}
}

// == testing ==

func TestInOrder(t *testing.T) {
	tree := NewTree()
	nums := []int{9, 7, 2, 4, 6, 10, 1, 5, 8, 3}
	for i := 0; i < len(nums); i++ {
		tree.Insert(ObjInt{nums[i]})
	}
	result := make(chan Obj, 10)
	go InOrder(tree, result)
	var previous Obj
	for obj := range result {
		fmt.Println(obj)
		if previous == nil {
			previous = obj
			continue
		}
		assertTrue(previous.Compare(obj) == -1, t,
			"Previous obj should be smaller than current object")
		previous = obj
	}
}

输出:

1
2
3
4
5
6
7
8
9
10

fatal error: all goroutines are asleep - deadlock!

请帮我翻译以上内容。

英文:

I'm building an asynchronous Btree in Go with channels, but I'm getting the error fatal error: all goroutines are asleep - deadlock! I don't know why 'cause I'm getting the values from the channel in a for loop with a buffered channel.

type Obj interface {
	Compare(node Obj) int
}

type Tree struct {
	Item        Obj
	Rigth, Left *Tree
	height      int16
}

func NewTree() *Tree {
	return &amp;Tree{Item: nil, Rigth: nil, Left: nil, height: 0}
}

func InOrder(t *Tree, chTree chan Obj) {
	if t != nil {
		InOrder(t.Left, chTree)
		chTree &lt;- t.Item
		InOrder(t.Rigth, chTree)
	}
}

// == testing ==

func TestInOrder(t *testing.T) {
	tree := NewTree()
	nums := []int{9, 7, 2, 4, 6, 10, 1, 5, 8, 3}
	for i := 0; i &lt; len(nums); i++ {
		tree.Insert(ObjInt{nums[i]})
	}
	result := make(chan Obj, 10)
	go InOrder(tree, result)
	var previous Obj
	for obj := range result {
		fmt.Println(obj)
		if previous == nil {
			previous = obj
			continue
		}
		assertTrue(previous.Compare(obj) == -1, t,
			&quot;Previous obj should be smaller than current object&quot;)
		previous = obj
	}
}

Output:

1
2
3
4
5
6
7
8
9
10

fatal error: all goroutines are asleep - deadlock!

答案1

得分: 3

你没有关闭通道。你会注意到它实际上是正确打印的,然后出现问题。

在对通道进行range循环时,像这样:

for obj := range result {
     //...
}

只有在调用close(result)时,循环才会退出。在这种情况下有点棘手,因为它是递归的。最终,我建议将对InOrder的调用包装如下:

func InOrder(t *Tree, chTree chan obj) {
    inOrder(t, chTree)
    close(chTree)
}

func inOrder(t *Tree, chTree chan Obj) {
    if t != nil {
        inOrder(t.Left, chTree)
        chTree <- t.Item
        inOrder(t.Rigth, chTree)
    }
}
英文:

You're not closing the channel. You'll notice that it's actually printing correctly, then freaking out.

In a range over a channel, like this:

for obj := range result {
     //...
}

The loop will only exit if you call close(result). In this case it's a bit tricky because of the recursive nature. Ultimately I'd recommend wrapping the call to InOrder like so:

func InOrder(t *Tree, chTree chan obj) {
    inOrder(t, chTree)
    close(chTree)
}

func inOrder(t *Tree, chTree chan Obj) {
    if t != nil {
        inOrder(t.Left, chTree)
        chTree &lt;- t.Item
        inOrder(t.Rigth, chTree)
    }
}

huangapple
  • 本文由 发表于 2014年4月27日 05:38:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/23316798.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定