Wie man richtig mit sync.Cond?
Ich habe Schwierigkeiten, herauszufinden, wie man richtig mit sync.Cond
. Was ich sagen kann, existiert eine race condition zwischen sperren der Schrank und die Berufung auf die Bedingung der Wait-Methode. In diesem Beispiel wird eine künstliche Verzögerung zwischen den beiden Zeilen in der main-goroutine zu simulieren, die race-condition:
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()
}
[Laufen auf den Spielplatz Gehen]
Dies bewirkt eine sofortige Panik:
fatal error: alle goroutines schlafen - deadlock! goroutine 1 [semacquire]: sync.runtime_Syncsemacquire(0x10330208, 0x1) /usr/local/go/src/runtime/sema.go:241 +0x2e0 sync.(*Cond).Warten(0x10330200, 0x0) /usr/local/go/src/sync/cond.go:63 +0xe0 main.main() /tmp/sandbox301865429/main.go:17 +0x1a0
Was mache ich falsch? Wie kann ich vermeiden, dass diese scheinbare race-condition? Gibt es eine bessere Synchronisation Konstrukt, das ich verwenden soll?
Edit: ich merke, ich sollte besser erklärt das problem, das ich zu lösen versuche hier. Ich habe eine lang andauernde goroutine lädt eine große Datei und eine Reihe von anderen goroutines, die Zugriff auf die HTTP-Header, wenn Sie verfügbar sind. Dieses problem ist schwieriger als es klingt.
Kann ich nicht die Kanäle, da nur eine goroutine würde dann den Wert. Und einige der anderen goroutines würde versuchen, rufen Sie die Header, lange nachdem Sie bereits verfügbar sind.
Den downloader goroutine könnte einfach speichern Sie die HTTP-Header in einer Variablen zu, und verwenden Sie einen mutex zum Schutz Zugang zu Ihnen. Dies bedeutet jedoch nicht, bieten eine Möglichkeit für die anderen goroutines "warten" für Sie verfügbar wird.
Ich hatte gedacht, dass beide eine sync.Mutex
und sync.Cond
zusammen erreichen könnten, dieses Ziel aber es scheint, dass dies nicht möglich ist.
Du musst angemeldet sein, um einen Kommentar abzugeben.
OP beantwortet seine eigene, aber nicht direkt die Antwort auf die ursprüngliche Frage, ich werde posten, wie man richtig mit
sync.Cond
.Die Sie nicht wirklich brauchen
sync.Cond
wenn Sie eine goroutine für jeden der schreiben und Lesen - eine einzigesync.Mutex
ausreichen würde, um die Kommunikation zwischen Ihnen.sync.Cond
könnte nützlich in Situationen, in denen mehrere Leser warten auf die gemeinsam genutzten Ressourcen zur Verfügung stehen.Spielplatz
Gesagt, dass die Nutzung von Kanälen ist immer noch die empfohlene Methode zum übergeben von Daten um, wenn die situation es zulässt.
Hinweis:
sync.WaitGroup
hier nur verwendet, um zu warten, bis die goroutines auf Ihre Ausführungen.Müssen Sie sicherstellen, dass c.Broadcast heißt nach Ihren Anruf.c.Warten. Die richtige version des Programms wäre:
https://play.golang.org/p/O1r8v8yW6h
http://play.golang.org/p/fBBwoL7_pm
Hier ein praktisches Beispiel mit zwei go-Routinen. Sie beginnen eine nach der anderen, aber die zweite wartet auf eine Bedingung, die Ausstrahlung durch den ersten, bevor Sie fortfahren:
Ausgang kann leicht variieren, da gehen bei der zweiten routine beginnen konnte, bevor der erste-und Umgekehrt:
https://gist.github.com/fracasula/21565ea1cf0c15726ca38736031edc70
Sieht aus wie Sie c.Warten auf Sendung, das wäre nie passiert mit Ihren Abständen.
Mit
das snippet scheint zu funktionieren http://play.golang.org/p/OE8aP4i6gY .Oder bin ich etwas fehlt, dass Sie versuchen zu erreichen?
Ich entdeckte schließlich einen Weg, dies zu tun und es sich nicht um
sync.Cond
an - nur die mutex.Wie funktioniert das?
Den mutex gesperrt ist, am Anfang die Aufgabe, sicherzustellen, dass irgendetwas Berufung
WaitFor()
blockiert werden. Sobald die Header sind verfügbar, und der mutex entsperrt, die durch die goroutine, jeder AufrufWaitFor()
ausgeführt wird, ein zu einer Zeit. Alle zukünftigen Anrufe (auch nach der goroutine endet) wird kein problem haben, sperren des mutex, da es immer Links freigeschaltet.sync.RWMutex
statt.Ja, Sie können mit einem Kanal zum Header übergeben, um mehrere Go-Routinen.