Non riesco a capire come utilizzare correttamente sync.Cond
. Da quello che posso dire, esiste una condizione di competizione tra il blocco dell'armadietto e l'invocazione del metodo di attesa della condizione. Questo esempio aggiunge un ritardo artificiale tra le due linee nel goroutine principale per simulare la condizione di competizione:Come utilizzare correttamente sync.Cond?
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()
}
questo provoca un panico immediato:
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
Nei sto sbagliando? Come posso evitare questa apparente condizione di gara? C'è un migliore costrutto di sincronizzazione che dovrei usare?
Edit: mi rendo conto che dovrei avere una migliore spiegato il problema che sto cercando di risolvere qui. Ho una goroutine di lunga data che scarica un file di grandi dimensioni e un certo numero di altre goroutine che hanno bisogno di accedere alle intestazioni HTTP quando sono disponibili. Questo problema è più difficile di quanto sembri.
Non riesco a utilizzare i canali poiché solo una goroutine riceverà il valore. E alcune delle altre goroutine potrebbero cercare di recuperare le intestazioni per molto tempo dopo che sono già disponibili.
La goroutine di download potrebbe semplicemente memorizzare le intestazioni HTTP in una variabile e utilizzare un mutex per salvaguardare l'accesso ad esse. Tuttavia, questo non fornisce un modo per le altre goroutine di "aspettare" che diventino disponibili.
Avevo pensato che sia un sync.Mutex
sia uno sync.Cond
insieme potessero raggiungere questo obiettivo ma sembra che questo non sia possibile.
E se non è possibile bloccare il mutex prima di lanciare il goroutine? Ad esempio, potrebbero esserci altre goroutine che chiamano Wait(). –
È possibile che, quando viene chiamato Broadcast, non venga notificata alcuna altra goroutine. Va anche bene - ma quello che non abbiamo menzionato entrambi - di solito la condizione è connessa con qualche stato. E Wait significa: non posso continuare mentre il sistema si trova in questo stato, aspetta. E Broadcast significa: lo stato è cambiato, tutti quelli che sono stati in attesa dovrebbero verificare se può continuare. Per favore descrivi più precisamente cosa viene calcolato in entrambe le goroutine e perché devono comunicarsi l'un l'altro. – lofcek
Scusa, avrei dovuto approfondire la domanda originale. Ho aggiunto una modifica che descrive esattamente ciò che sto cercando di fare. –