2017-01-17 5 views
0

私はGoの初心者です、私はこのコードを書いて、デッドロック状態に入ることを望みますが失敗しました。このGoプログラムがデッドロック状態になるのはなぜですか?

var mux sync.Mutex 

func main() { 
    runtime.GOMAXPROCS(1) 
    for i := 0; i < 3; i++ { 
    go func() { 
     log.Println("Trying to Lock the Mux") 
     mux.Lock() 
     log.Println("The mux is Locked") 
    }() 
    } 
    runtime.Gosched() 
} 
//Output: 
//2017/01/17 08:59:42 Trying to Lock the Mux 
//2017/01/17 08:59:42 The mux is Locked 
//2017/01/17 08:59:42 Trying to Lock the Mux 
//2017/01/17 08:59:42 Trying to Lock the Mux 

ご覧のとおり、このコードはうまく動いて何かを印刷し、デッドロックエラーなしで終了します。私が知っているのは、最初のものです。go func(){} goroutineはmuxを返してロックしてから終了しました。しかし、他の2つのゴルーチンは、マルチプレクサが既にブロックされているためブロックされます。

runtime.Gosched機能()は右のみFIFOキュー(runtime.GOMAXPROCS(1))にメインゴルーチンをプッシュする必要がありますか?それはなぜキューの左にある2つのgoroutineの前にexcuteすることができますか?

ところで、この次のコードは期待

var mux sync.Mutex 

func main() { 
    runtime.GOMAXPROCS(1) 
    var wg sync.WaitGroup 
    wg.Add(3) 
    for i := 0; i < 3; i++ { 
     go func() { 
      defer wg.Done() 
      log.Println("Trying to Lock the Mux") 
      mux.Lock() 
      log.Println("The mux is Locked") 

     }() 
    } 
    wg.Wait() 
} 

感謝としてデッドロックエラーが返されます!あなたのコードの場合

+1

ランタイムはここには何もしないので、意図はわかりません。あなたはプログラムがデッドロックしていない、メインのgoroutineは継続して終了します。 – JimB

+0

私が知っているように、Gosched()はメインのゴルーチンをキューに押し戻し、すべてのゴルーチンが完了するのを待ちます。 – MikeZhang

+0

Goschedがブロックキューにgoroutineを置くという考えがどこにあるのか分かりませんが、それは間違っています。 "Goschedはプロセッサを生成し、他のゴルーチンを実行できるようにします。現在のゴルーチンを一時停止しないので、実行は自動的に再開します。" – JimB

答えて

1

var mux sync.Mutex 

func main() { 
    runtime.GOMAXPROCS(1) 
    for i := 0; i < 3; i++ { 
    go func() { 
     log.Println("Trying to Lock the Mux") 
     mux.Lock() 
     log.Println("The mux is Locked") 
    }() 
    } 
    runtime.Gosched() 
} 

デッドロックが

FUNC(のm *ミューテックス)ロック()

ロックメートルをロックするために、ありません。ロックが既に使用されている場合は、 呼び出し元のgoroutineがmutexが使用可能になるまでブロックします。

だから、2番目と3番目のゴルーチンだけがそこに待っています。これはbusy waitingです。メインのゴルーチン出口があるので、2番目と3番目のゴルーチンも存在します。

2

デッドロックは、すべてのゴルーチンが待機状態(ロック待ちまたはチャンネルからの読み込み中など)の状態です。理由は簡単です。もしそれらのすべてが待っているなら、待つゴルーチンのいずれかにつながる何かを行うことができる人はいません。あなたの主な機能は、ゴルーチンでもあり、待機状態にはありません。メインのゴルーチンが終了すると、プロセスも終了します。

runtime.Gosched機能は、()の右 のみFIFOキュー(runtime.GOMAXPROCS(1))に、メインゴルーチンをプッシュする必要がありますか?それはなぜキューに既に左の2つのゴルーチンの前に をexcuteすることができますか?

キューはスケジュールキューです。ランタイムは、キューからゴルーチンを選択し、しばらく実行し、一時停止し、別のゴルーチンを選択します。

+0

このスケジュールキューはFIFOキューではありません。 – MikeZhang

+0

これはFIFOですが、goroutines iのスケジューリングに使用されます。ランタイムは、このキューからFIFOポリシーを使用してスケジュールするためのゴルーチンを選択します。 FIFOは、キューから項目を配置したりフェッチしたりする方法です。これらの項目で行うことは、FIFOの内容ではありません。 – Ankur

関連する問題