Wie verwende ich sync.Cond richtig?

Ich habe Probleme herauszufinden, wie man @ richtig benutsync.Cond. Soweit ich weiß, besteht eine Race-Bedingung zwischen dem Sperren des Schließfachs und dem Aufrufen der Wait-Methode der Bedingung. In diesem Beispiel wird eine künstliche Verzögerung zwischen den beiden Linien in der Hauptgoroutine hinzugefügt, um den Rennzustand zu simulieren:

package main

import (
    "sync"
    "time"
)

func main() {
    m := sync.Mutex{}
    c := sync.NewCond(&m)
    go func() {
        time.Sleep(1 * time.Second)
        c.Broadcast()
    }()
    m.Lock()
    time.Sleep(2 * time.Second)
    c.Wait()
}

[Run on the Go Spielplatz]

Dies löst sofort eine Panik aus:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Syncsemacquire(0x10330208, 0x1)
    /usr/local/go/src/runtime/sema.go:241 +0x2e0
sync.(*Cond).Wait(0x10330200, 0x0)
    /usr/local/go/src/sync/cond.go:63 +0xe0
main.main()
    /tmp/sandbox301865429/main.go:17 +0x1a0

Was mache ich falsch? Wie vermeide ich diesen offensichtlichen Rennzustand? Gibt es ein besseres Synchronisationskonstrukt, das ich verwenden sollte?

Bearbeiten Mir ist klar, dass ich das Problem, das ich hier zu lösen versuche, besser hätte erklären sollen. Ich habe eine lang laufende Goroutine, die eine große Datei herunterlädt, und eine Reihe anderer Goroutinen, die Zugriff auf die HTTP-Header benötigen, wenn sie verfügbar sind. Dieses Problem ist schwieriger als es sich anhört.

Ich kann keine Kanäle verwenden, da dann nur eine Goroutine den Wert erhalten würde. Und einige der anderen Goroutines würden versuchen, die Header abzurufen, lange nachdem sie bereits verfügbar sind.

Die Downloader-Goroutine könnte einfach die HTTP-Header in einer Variablen speichern und einen Mutex verwenden, um den Zugriff darauf zu sichern. Auf diese Weise können die anderen Goroutinen jedoch nicht darauf warten, dass sie verfügbar sind.

Ich hatte gedacht, dass sowohl einsync.Mutex undsync.Cond together könnte dieses Ziel erreichen, aber es scheint, dass dies nicht möglich ist.

Antworten auf die Frage(14)

Ihre Antwort auf die Frage