2010-03-19 13 views
15

Sto cercando di conoscere le variabili di condizione. Mi piacerebbe sapere quali sono le situazioni comuni in cui vengono utilizzate le variabili di condizione.Quali sono gli usi comuni delle variabili di condizione in C++?

Un esempio è in una coda di blocco, in cui due thread accedono alla coda: il thread del produttore inserisce un elemento nella coda, mentre il thread del consumatore apre un elemento dalla coda. Se la coda è vuota, il thread del consumatore è in attesa finché non viene inviato un segnale dal thread del produttore.

Quali sono le altre situazioni di progettazione in cui è necessario utilizzare una variabile di condizione?

Preferirei esempi basati sull'esperienza, come quelli in applicazioni live reali.

+1

Questo dovrebbe essere wiki della comunità? – jasonline

+0

Poiché non si sta cercando una risposta specifica e solo "risposte" più generali, probabilmente. Ma io sono più sul recinto di questo, potresti voler aspettare il no o il yay dagli altri. – GManNickG

+2

+1 Prendi questi punti reputazione ben meritati mentre puoi per questa bella domanda :-) –

risposta

2

Un uso di variabili di condizione che è un po 'più complicato di una semplice coda di messaggi, è di "condividere un blocco", dove thread differenti sono in attesa di condizioni sottilmente diverse della stessa natura di base. Ad esempio, hai una cache web (molto brillante, semplificata). Ogni voce nella cache ha tre possibili stati: non presente, IN_PROGRESS, COMPLETE.

getURL: 
    lock the cache 
    three cases for the key: 
     not present: 
      add it (IN_PROGRESS) 
      release the lock 
      fetch the URL 
      take the lock 
      update to COMPLETE and store the data 
      broadcast the condition variable 
      goto COMPLETE 
     COMPLETE: 
      release the lock and return the data 
     IN_PROGRESS: 
      while (still IN_PROGRESS): 
       wait on the condition variable 
      goto COMPLETE 

ho in pratica utilizzato il modello di attuare una variante della funzione POSIX pthread_once senza alcun aiuto dal programmatore. Il motivo per cui non ho potuto utilizzare un semaforo o un lucchetto per once_control e solo eseguire l'inizializzazione sotto il blocco, è che la funzione non è stata lasciata fallire e il once_control ha avuto solo un'inizializzazione banale. Del resto, lo stesso pthread_once non ha codici di errore definiti, quindi implementarlo per riuscire a fallire non lascia il tuo chiamante con buone opzioni ...

Naturalmente con questo modello devi stare attento al ridimensionamento. Ogni volta che viene completata un'inizializzazione, ogni thread di attesa si attiva per afferrare il blocco. Quindi, quando si progetta il sistema, si pensa molto attentamente alla condivisione e quindi si decide di non essere disturbati a fare nulla per implementarlo realmente finché non si vedono problemi di prestazioni comprovati.

1

Un esempio, oltre al modello produttore-consumatore, che hai già menzionato è l'uso in barrier synchronization. Quando i fili entrano nella barriera, se ci sono ancora altri fili che devono entrare nella barriera, allora aspettano una variabile di condizione. L'ultimo thread per entrare nella barriera segnala la condizione.

+0

@ Michael: Non ho molta familiarità con le barriere ... ma nel tuo esempio, stai dicendo che hai usato barriere con una variabile di condizioni separata? Ho pensato che è possibile implementare la situazione di cui sopra utilizzando solo le barriere e non è necessaria una variabile di condizione separata? – jasonline

+0

@jasonline, quindi, puoi usare le barriere fornite da pthreads, ma puoi anche implementare la tua barriera usando un mutex e una variabile di condizione (che è il modo in cui i pthreads forniscono più probabilmente). Quando entri nella barriera, blocchi il mutex, incrementa il conteggio e memorizza il senso di barriera. Se il conteggio ha raggiunto il massimo, resettate il conteggio a zero, invertite il senso della barriera, segnalate la condizione ed uscite dalla barriera. Altrimenti, si attende la condizione, finché il senso di barriera non è opposto a quello memorizzato. –

+0

Ah, sì. Ho capito il tuo punto. Grazie. – jasonline

0

L'ho usato per inviare messaggi sincronizzati, dove è stato aggiunto un oggetto di sincronizzazione.
L'oggetto di sincronizzazione consisteva in una variabile di condizione con un booleano "pronto".
Nella funzione syncMsg :: send(), c'era un sync-> wait() e nella funzione syncMsg :: handle(), c'era un sync-> go().

Dovrebbe essere usato giudiziosamente a causa di possibili deadlock.

0

Io utilizzo le variabili di condizione anziché gli oggetti evento Win32 soggetti a errore. Con condvars, non devi preoccuparti così tanto di segnalazione spuria. È anche più semplice attendere che si verifichino più eventi.

I condvari possono anche sostituire i semafori, perché sono più generici.

0

So che questo non è molto utile, ma io uso la variabile di condizione ogni volta che voglio che un thread attenda che accada qualcosa, o aspetta solo fino a quando succede qualcosa.

Un modello molto comune per cui io uso una variabile condizione è un thread in background che si sveglia ogni pochi minuti per fare un po 'di elaborazione poi torna a dormire. All'arresto, il thread principale segnala al thread di sfondo di terminare e quindi unirlo alla fine. Il thread in background attende la condizione con un timeout, per eseguire la sua sospensione.

Il thread in background segue questa logica di base

void threadFunction() { 
    initialisation(); 

    while(! shutdown()) { 
     backgroundTask(); 

     shutdown_condition_wait(timeout_value); 
    } 

    cleanup(); 
} 

In questo modo l'arresto thread in background tempestivamente e con grazia.

Se ho un certo numero di tali fili principali segnali delle funzioni ciascuno all'arresto unisce quindi ogni uno dopo l'altro. Ciò consente a ciascun componente del thread di arrestarsi in parallelo.

Problemi correlati