Каналы тупик

Я строю асинхронное B-дерево в Go с каналами, но получаю ошибку fatal error: all goroutines are asleep - deadlock! Не знаю почему, потому что я получаю значения из канала в цикле for с буферизованным каналом.

type Obj interface {
    Compare(node Obj) int
}

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

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

func InOrder(t *Tree, chTree chan Obj) {
    if t != nil {
        InOrder(t.Left, chTree)
        chTree <- 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 < 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!

person sescob27    schedule 26.04.2014    source источник


Ответы (1)


Вы не закрываете канал. Вы заметите, что он на самом деле печатает правильно, а затем сходит с ума.

В 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)
    }
}
person LinearZoetrope    schedule 26.04.2014
comment
большое спасибо, я знал, что должен закрыть канал, но не знал, как это сделать с помощью рекурсивной функции - person sescob27; 27.04.2014