2010-10-27 17 views
18

Sto utilizzando una coda per comunicare tra thread. Ho un lettore e più thread di scrittore. La mia domanda è: ho bisogno di bloccare la coda ogni volta che uso push/front/pop dalla coda per il lettore? Posso fare qualcosa di simile al seguente:Sicurezza thread per coda STL

//reader threads 
getLock(); 
get the number of elements from the queue 
releaseLock(); 

int i = 0; 
while(i < numOfElements){ 
    queue.front(); 
    queue.pop(); 
    i++ 
} 

L'idea è che voglio ridurre la granularità del codice chiuso e poiché il thread di scrittura avrebbe scritto solo per la parte posteriore della coda e c'è solo un unico lettore filo. Finché ottengo il numero di elementi, allora potrei ottenere gli elementi dalla coda O devo includere lo front() e pop() anche nel blocco?

risposta

8

Qualsiasi tipo che non indichi esplicitamente le sue garanzie di sicurezza del thread dovrebbe sempre essere controllato da un mutex. Detto questo, lo stdlib della tua implementazione potrebbe consentire alcune varianti di questo - ma non puoi sapere per tutte le implementazioni di std :: queue.

Come std :: queue esegue il wrapping di un altro contenitore (è un adattatore del contenitore), è necessario esaminare il contenitore sottostante, che di default designa.

È possibile trovare più semplice, migliore o più portatile scrivere il proprio adattatore contenitore che fornisce le garanzie necessarie. Non so nulla che faccia esattamente questo per una coda in Boost.

Non ho visto abbastanza C++ 0x per sapere se ha qualche soluzione per questo pronto all'uso, ma potrebbe essere un'altra opzione.

+4

C++ 0x ha Atomics, quindi consente programmatori di scrivere senza blocchi (algoritmo thread-safe) e fornisce standard mutex, ma non ha nulla di pronto all'uso. – GManNickG

2

Questo è assolutamente dipendente dall'implementazione. Lo standard C++ fa menzione di thread o sicurezza dei thread, quindi se questo funzionerà o meno dipende da come la tua implementazione gestisce gli elementi in coda.

Nel tuo caso, il lettore sta effettivamente facendo scoppiare la coda, che è considerata un'operazione di scrittura. Dubito che qualsiasi implementazione comune garantisca effettivamente la sicurezza del thread in questo caso, quando più thread scrivono simultaneamente su un contenitore. Almeno VC++ non:

Per le letture nello stesso oggetto, l'oggetto è sicuro da thread per la lettura quando nessun writer su altri thread.

Per le scritture sullo stesso oggetto, l'oggetto è thread-safe per la scrittura da un thread quando nessun lettore su altri thread.

9

Come altri hanno già menzionato, i contenitori standard non sono necessari per garantire la sicurezza del thread, quindi ciò che si richiede non può essere implementato in modo portabile. È possibile ridurre il tempo in cui il thread del lettore blocca i writer utilizzando 2 code e un puntatore della coda che indica la coda attualmente utilizzata dai writer.

Ogni scrittore farebbe:

  • blocco Acquisisci
  • elemento di spinta (s) nella coda attualmente puntato dal puntatore coda di
  • blocco di uscita

il lettore può poi fare il seguente:

  • Acquir e bloccare
  • Passa puntatore coda per puntare alla seconda coda
  • blocco di uscita
  • elementi di processo dalla prima coda
+0

Come funzionerebbe lo scrittore? – GManNickG

+2

Lo scrittore si accoderebbe sempre a qualsiasi coda a cui punta attualmente il puntatore della coda (dopo aver acquisito il blocco). In questo scenario, il blocco protegge la coda a cui il puntatore attualmente fa riferimento (e il puntatore stesso); l'altra coda ("prima coda") può essere elaborata dal lettore senza tenere il blocco. –

1

A volte si riesce a risolvere un sacco di concorrenza mal di testa, evitando Stato o la condivisione di risorse tra filettature. Se si dispone di più thread che accedono a un contenitore contemporaneamente per spingere nel proprio lavoro, provare a farli funzionare su contenitori dedicati. In punti specifici, quindi, raccogli gli elementi dei contenitori sul contenitore centrale in modo non simultaneo.

Se è possibile evitare la condivisione di stato o risorse tra thread, non si verificano problemi durante l'esecuzione di thread contemporaneamente. I thread quindi non devono preoccuparsi l'uno dell'altro, perché sono completamente isolati e non hanno alcun effetto l'uno sull'altro.

1

L'intuizione è corretta: anche se non è possibile contare sulla coda STD per essere thread-safe, una coda deve essere protetta da thread in base al modello.

Un bel chiarito perché questo è il caso e un'implementazione standard di sicurezza filetto, bloccare code liberi in C++ è dato da van Dooren

+2

l'implementazione ingenua della coda senza blocco è solo parzialmente "thread safe" solo per il caso speciale singolo produttore, singolo consumatore e alcune altre assunzioni sulle barriere della memoria e sulla lettura/scrittura atomica nel codice generato dal compilatore. È comunque possibile implementare una coda di sicurezza thread lock veramente libera, ma non è così semplice. – Leo