7

ばかげた基本的なスレッド化の演習として、私は睡眠中の床屋問題を golang で実装しようとしました。チャネルを使用すると、これは非常に簡単なはずですが、ハイゼンバグに遭遇しました。つまり、診断しようとすると、問題が消えます!

以下を検討してください。このmain()関数は整数 (または「顧客」) をshopチャネルにプッシュします。barber()チャネルを読み取り、shop「顧客」の髪をカットします。fmt.Print関数にステートメントを挿入するcustomer()と、プログラムは期待どおりに実行されます。そうでなければ、barber()誰の髪も決して切らない。

package main

import "fmt"

func customer(id int, shop chan<- int) {
    // Enter shop if seats available, otherwise leave
    // fmt.Println("Uncomment this line and the program works")
    if len(shop) < cap(shop) {
        shop <- id
    }
}

func barber(shop <-chan int) {
    // Cut hair of anyone who enters the shop
    for {
        fmt.Println("Barber cuts hair of customer", <-shop)
    }
}

func main() {
    shop := make(chan int, 5) // five seats available
    go barber(shop)
    for i := 0; ; i++ {
        customer(i, shop)
    }
}

何が起こっているのか分かりますか?

4

2 に答える 2

5

問題は、Go のスケジューラーの実装方法です。現在のゴルーチンは、システム コールまたはブロッキング チャネル操作を行う場合にのみ、他のゴルーチンに譲ることができます。fmt.Printlnシステムコールを行い、ゴルーチンに譲歩の機会を与えます。それ以外の場合はありません。

実際には、これはあまり重要ではありませんが、このような小さな問題の場合は、時々発生することがあります。

また、チャネルで非ブロッキング送信を行う、より慣用的で際どさの少ない方法は次のとおりです。

func customer(id int, shop chan<- int) {
    // Enter shop if seats available, otherwise leave
    select {
    case shop <- id:
    default:
    }
}

あなたのやり方では、あなたが実際に送信するまでに、顧客は理髪店の外で待っているlen(shop)可能性があります。

于 2012-04-14T04:52:33.797 に答える
1

runtime.GOMAXPROCS(2)main の先頭に追加すると解決しますか?

于 2012-04-14T04:48:24.453 に答える