Una variabile di condizione è sempre associata ad alcuni tipi di lock; questa può venir passata oppure creata automaticamente. (Passarne una torna utile quando alcune variabili di condizione devono condividere lo stesso lock).
Una variabile di condizione possiede i metodi acquire() e release() che chiamano i metodi corrispondenti al lock associato. Possiede anche i metodi wait(), notify() e notifyAll(). Questi tre devono essere chiamati solo quando il thread chiamante ha acquisito il lock.
Il metodo wait() rilascia il lock, e si blocca fino a che non venga risvegliato da una chiamata a notify() o notifyAll() per la stessa variabile di condizione in un altro thread. Una volta risvegliato, riacquisisce il lock e termina. È anche possibile specificare un timeout.
Il metodo notify() risveglia uno dei thread in attesa della variabile di condizione, se ce ne sono. Il metodo notifyAll() risveglia tutti i thread in attesa della variabile di condizione.
Nota: i metodi notify() e notifyAll() non rilasciano il lock; questo significa che il thread o i thread risvegliati, non restituiranno dalla loro chiamata wait() immediatamente, ma solo quando il thread che ha chiamato la notify() o la notifyAll() abbandona alla fine la proprietà del lock.
Consiglio: usando le variabili di condizione lo stile di programmazione tipico si serve dei lock per sincronizzare l'accesso ad alcuni stati condivisi; i thread che sono interessati in un particolare cambio di stato chiamano la wait() ripetutamente fino a che vedano lo stato desiderato, mentre i thread che vogliono modificare lo stato chiamano notify() o notifyAll() in modo che possa essere uno stato desiderato da uno dei thread in attesa. Per esempio, il codice seguente è una situazione generica di produttore-consumatore con buffer di capacità illimitata:
# Consuma un elemento cv.acquire() while not an_item_is_available(): cv.wait() get_an_available_item() cv.release() # Produce un elemento cv.acquire() make_an_item_available() cv.notify() cv.release()
Per scegliere fra notify() e notifyAll(), considerare se un cambio di stato può essere interessato a solo uno o più thread in attesa. Per esempio in una tipica situazione di produttore-consumatore, aggiungere un oggetto al buffer necessita solo del risveglio di uno dei thread consumatori.
[lock]) |
None
, deve essere
un oggetto Lock o RLock, ed è usato come il lock
sottostante. Altrimenti, viene creato un nuovo oggetto RLock
ed usato come il lock sottostante.
*args) |
) |
[timeout]) |
Il metodo rilascia il lock sottostante, e si blocca fino a che non sia risvegliato da una chiamata a notify() o notifyAll() per la stessa variabile di condizione in un altro thread, o fino a che non giunga il timeout facoltativo. Una volta risvegliato o andato in timeout, riacquisisce il lock e termina.
Quando l'argomento timeout è presente e diverso da None
,
dovrebbe essere un numero in virgola mobile che specifica un timeout
in secondi per l'operazione (o frazioni di secondo).
Quando il lock sottostante è un RLock, non viene rilasciato usando il suo metodo release(), visto che ciò potrebbe non sbloccare realmente il lock quando questo è stato acquisito più volte ricorsivamente. Invece, viene usata un'interfaccia interna della classe RLock, che lo sblocca realmente anche quando è stato acquisito ricorsivamente alcune volte. Un'altra interfaccia interna è quindi usata per ripristinare il livello di ricorsione quando il lock viene riacquisito.
) |
Questo metodo risveglia uno dei thread in attesa della variabile di condizione, se ce ne sono; non effettua alcuna operazione se non ci sono thread in attesa.
L'implementazione corrente risveglia esattamente un thread, se ce ne sono in attesa. Comunque, non è sicuro fidarsi di questo comportamento. Un'implementazione futura ottimizzata potrà occasionalmente risvegliare più di un thread.
Nota: Il thread risvegliato non restituisce realmente dalla sua chiamata wait() fino a che non possa riacquisire il lock. Visto che la notify() non rilascia il lock, lo dovrebbe fare il chiamante.
) |
Vedete Circa questo documento... per informazioni su modifiche e suggerimenti.