2012-12-28 6 views
7

私はGoを学習しており、GoToursからthis lessonに取り組んでいます。ここに私がこれまで持っているものがあります。チャネルのデッドロックの例外をキャッチするにはどうすればよいですか?

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)  
    } 
} 

ご覧のとおり、私はチャンネルに書き込んだ値を印刷してウォーク機能をテストしようとします。しかし、私は次のエラーが発生します。

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 

このエラーは、私がチャンネルをcloseことはありませんので、私は考えて期待されなければなりません。しかし、このデッドロックエラーを "キャッチ"してプログラムで処理できる方法はありますか?

+2

:あなたは並列でツリーを走査する場合は、さらに変更を加える必要があります

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) } } 

を実行されていません。何も実行されていない場合、例外を "キャッチ"できるゴルーチンは存在しません。 – newacct

+0

ありがとう!そうであれば、「n回」の回数を読み込んだ後、チャンネルから読み上げをやめる方法がありますか?「n」はチャンネルに書き込んだ回数です。 – dangerChihuahua007

+2

別のヒント:ウォーク機能でチャンネルの方向を指定することをお勧めします。 func Walk(t * tree.Tree、ch chan < - int) –

答えて

6

デッドロックは、プログラム内のBUGを表すnilポインタの尊重に似ています。このクラスのエラーは、通常、この理由で回復できません。

lbonnが言及しているように、ここでの問題はチャンネルを「閉じる(myChan)」必要があることです。範囲外のループを実行しないと、ループは次の要素を永遠に待つことになります。

あなたはこのような何か試すことができます:デッドロックは、すべてのゴルーチンことを意味し、定義によると

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) 
    } 
} 
5

いいえ、デッドロックから回復することはできません。

+1

ありがとう!しかし、私がチャンネルに送ったアイテムをどのようにプリントアウトするのですか? – dangerChihuahua007

7

このデッドロックは、rangeコンストラクトがチャネルが閉じられるまで繰り返されるためです。 http://golang.org/ref/spec#For_statements

ここでは、ツリーが完全に調査されたときにチャネルを閉じるか、別の構造を使用する必要があります。

この例では、ツリーのサイズが10であることがわかっているので、forループを1から10まで実行し、各繰り返しでチャネルから一度だけ読み込むことができます。

関連する問題