2016-04-28 8 views
0

Ich versuche einen Kanal zu testen, der auf einer unendlichen for-Schleife läuft. Ich denke, ich habe einen Weg gefunden, es zu tun, aber ich bin nicht sicher, ob es eine gültige Möglichkeit ist, bedingte Variablen zu verwenden. Ich bin mir auch nicht sicher, ob dieser Ansatz zu einer Wettlaufsituation neigt. Da die for-Schleife auf einer eigenen Routine läuft, ist es möglich, dass der Kanal bis zum Zeitpunkt "cond.Wait()" leer ist? Wenn dies passiert wäre, würde ich für immer hängen bleiben? In allen Beispielen, die ich bei der Verwendung von bedingten Variablen gesehen habe, sind sie normalerweise von einer for-Schleife begleitet, die die Wartezeit umgibt. Brauche ich das hier? Meine Frage: Ist der Ansatz, den ich hier verwende, falsch? Ist dies eine gültige/idiomatische Verwendung von bedingten Variablen?Wie kann ich eine Goroutine testen, die auf einer unendlichen for-Schleife mit sync.Cond läuft?

package main 

import (
    "fmt" 
    "sync" 
) 

var doStuffChan chan bool 
var cond *sync.Cond 
var result string 

func main() { 
    doStuffChan = make(chan bool, 10) 
    cond = &sync.Cond{L: &sync.Mutex{}} 
    go startDoStuffLoop() 

    doStuffChan <- true 

    cond.L.Lock() 
    cond.Wait() 
    cond.L.Unlock() 

    fmt.Println(result) 
} 

func startDoStuffLoop() { 
    for { 
     <-doStuffChan 
     result = "success" 
     cond.Broadcast() 
    } 
} 

Antwort

2

In meinen Augen sind Sie in allen Ihren Annahmen richtig. Zur Vermeidung von Kanalentleerung verwendet nur

close(doStuffChan) 

statt doStuffChan <- true, da Sie nil von geschlossenem Kanal empfangen können, für immer. Sie warten mit Schleife, um zu überprüfen, bevor Bedingung wahr war, da es in den meisten Fällen eine Bedingung ist. Wenn Sie die Channel-Guard-Signalisierung im Kanal und das Broadcasting nicht mit Lock schließen möchten, wodurch die Operationspräzedenz deterministisch wird.

func main() { 
    doStuffChan = make(chan bool) 
    cond = &sync.Cond{L: &sync.Mutex{}} 
    go startDoStuffLoop() 

    cond.L.Lock() 
    doStuffChan <- true 
    cond.Wait() 
    cond.L.Unlock() 

    fmt.Println(result) 
} 

func startDoStuffLoop() { 
    for { 
     <-doStuffChan 
     result = "success" 
     cond.L.Lock() 
     cond.Broadcast() 
     cond.L.Unlock() 
    } 
} 

Siehe funktioniert es https://play.golang.org/p/1S6VW7nIoV Beide Versionen sind jedoch THREAD.

+0

Wenn ich den doStuffChan schließe, funktioniert es nicht mehr. Außerdem muss ich den Kanal offen halten, um zukünftige Ereignisse zu empfangen. Grundsätzlich muss ich prüfen, ob eine Iteration von doStuffLoop läuft. Aber der Kanal sollte für zukünftige Operationen offen bleiben. https://play.golang.org/p/gsOwifVkOZ – circuitry

+0

Auch ich bin mir immer noch nicht sicher, ob es möglich ist, hier eine Race-Bedingung zu treffen. – circuitry

+0

Nur eine Antwort aktualisiert – Uvelichitel