3

相互に整数を送信する 3 つの同時進行の go ルーチンを作成したいと考えています。これで、コードは適切にコンパイルされましたが、最初の実行後に「すべてのゴルーチンがスリープ状態です - デッドロック!」というエラーが発生します。エラーを見つけようとしましたが、コードロジックでエラーを見つけることができませんでした。コードの間違いを見つけるのを手伝ってくれますか? 私のコードを以下に示します。前もって感謝します。

package main

import "rand"

func Routine1(command12 chan int, response12 chan int, command13 chan int, response13 chan int) {
    for i := 0; i < 10; i++ {
        y := rand.Intn(10)
        if y%2 == 0 {
            command12 <- y
        }

        if y%2 != 0 {
            command13 <- y
        }
        select {
        case cmd1 := <-response12:
            print(cmd1, " 1st\n")
        case cmd2 := <-response13:
            print(cmd2, " 1st\n")
        }
    }
    close(command12)
}

func Routine2(command12 chan int, response12 chan int, command23 chan int, response23 chan int) {
    for i := 0; i < 10; i++ {
        select {
        case x, open := <-command12:
            {
                if !open {
                    return
                }
                print(x, " 2nd\n")
            }

        case x, open := <-response23:
            {
                if !open {
                    return
                }
                print(x, " 2nd\n")
            }
        }

        y := rand.Intn(10)
        if y%2 == 0 {
            response12 <- y
        }

        if y%2 != 0 {
            command23 <- y
        }

    }
}

func Routine3(command13 chan int, response13 chan int, command23 chan int, response23 chan int) {
    for i := 0; i < 10; i++ {
        select {
        case x, open := <-command13:
            {
                if !open {
                    return
                }
                print(x, " 2nd\n")
            }
        case x, open := <-command23:
            {
                if !open {
                    return
                }
                print(x, " 2nd\n")
            }
        }

        y := rand.Intn(10)
        if y%2 == 0 {
            response13 <- y
        }

        if y%2 != 0 {
            response23 <- y
        }

    }
}

func main() {
    command12 := make(chan int)
    response12 := make(chan int)
    command13 := make(chan int)
    response13 := make(chan int)
    command23 := make(chan int)
    response23 := make(chan int)

    go Routine1(command12, response12, command13, response13)
    go Routine2(command12, response12, command23, response23)
    Routine3(command13, response13, command23, response23)
}

Routine2 と Routine3 を go ルーチンとして宣言すると、なぜ出力が [出力なし] になるのか、誰か教えてください。私は GO が初めてで、「​​http://golang.org/doc/effective_go.html#concurrency」から理解したように、go は同じアドレス空間で他のゴルーチンと並行してゴルーチンを実行するために使用されます。では、すべてのルーチンが実行されているのに、出力が [出力なし] であるという問題は何ですか。

プログラムをより明確にするために:実際に私がするのは、2つのルーチンごとに2つのチャネルを作成し、1つのチャネルを使用してintを他のチャネルに送信し、そのルーチンから別のチャネルでintを受信することです。たとえば、ルーチン 1 と 3 の間のチャネルは command13 と response13 です。ルーチン 1 は、command13 を使用して int を送信し、response13 を使用してルーチン 3 との間で int を受信します。さて、3 つのルーチンが並行しており、受信メッセージまたは送信メッセージを処理する特定のルーチンがあるのに、なぜデッドロックに陥るのでしょうか?

4

2 に答える 2

8
go Routine1(command12, response12,command13, response13 )
go Routine2(command12, response12,command23, response23) // go routine
Routine3(command12, response12,command23, response23 )

これにより、新しいゴルーチンで Routine1 が開始され、メインのゴルーチンが次のステートメントに進みます。したがって、Routine1 と Routine2 は同時に実行されますが、Routine3 は Routine2 の終了後に開始されます。ここで別の「go」ステートメントを見逃す可能性があります。

それから、私はあなたのプログラムに従おうとしていました。Routine1 では、

command13 <- y

これにより、メッセージを受信できる別のゴルーチンの準備が整うまで、Routine1 がブロックされます。y := <-command13したがって、別のゴルーチンにa が必要です。

しかしここで、他の 2 つのゴルーチンのパラメーターを詳しく見てみましょう。

Routine2(command12, response12,command23, response23)
Routine3(command12, response12,command23, response23 )

ご覧のとおり、どのゴルーチンも command13 にアクセスできません (ただし、command12 を 2 回渡しています)。したがって、Routine1 も Routine2 も Routine3 も続行できません。デッドロック!

製図板に戻ることをお勧めします。最初に何をしようとしているのかを考え、予想されるメッセージの流れについていくつかの図を描いてから、その動作を実装してみてください。

現時点では、プログラムをデバッグするのは非常に困難です。

  • あなたが何をしようとしているのかわからない。メッセージ フローなどについての詳細な説明はありません。実際、コードにはドキュメントがまったく含まれていません。
  • response23呼び出されるパラメーターなどに呼び出されるチャネルを渡しますresponse13。それらを混同するのはとても簡単です。
  • command12 などの一般的な名前はすべて、このチャネルが何をすべきかを理解するのを難しくしています
  • ソースコードを投稿する前に、ソースコードを投稿することをお勧めしgofmtます:)

出発点として、 Go チュートリアルの「素数」の例をお勧めします。この例では、可能な素数が 1 つのゴルーチンから別のゴルーチンに渡されます。さらに、この例には、メッセージ フローに関する優れたグラフィックスと、非常に優れた説明も含まれています。あなたはそれが好きかもしれません。

于 2011-11-23T18:11:11.657 に答える
3

チャンネルをブロック チャンネルとして宣言しました。いずれかのチャネルから送信または受信を試みるとすぐに、ゴルーチンはその値が読み取られるまで、または値を受信するまでブロックされます。

たとえば、そのゴルーチンRoutine1を呼び出すと、他のcommand12 <- y何かがyチャネルを引き離すまでブロックされます。についても同様ですcommand13。これらの送信をループで実行していて、同期的Routine2Routine3実行しているため、デッドロックの問題が発生します。

あなたが知っているように、チャネルもゴルーチンもデッドロックに対する保証ではありません。代わりに、それらは通常、同時に実行されているプログラムのさまざまな部分を同期および調整するために使用されます。

Routine2Routine3もゴルーチンである場合、プログラムの終了を止めるものは何もありません。そのため、その場合は出力が得られません。

一枚の紙を持って座って、プログラム内のさまざまな要素間の相互作用を引き出すことはおそらく有益でしょう.

于 2011-11-23T18:14:43.817 に答える