2012-01-28 14 views
29

Ho più thread contemporaneamente chiamando push_back() su un oggetto condiviso di std::vector. Il thread std::vector è sicuro? O devo implementare personalmente il meccanismo per renderlo sicuro?
Voglio evitare di fare extra "blocco e liberazione" funziona perché sono un utente di libreria piuttosto che un designer di libreria. Spero di cercare soluzioni thread-safe esistenti per il vettore. Che ne dite di boost::vector, che è stato introdotto di recente da boost 1.48.0 in poi. È thread-safe?std :: vector or boost :: vector thread safe?

+0

Questo deve essere un dup. Ma no, nessuno dei contenitori standard è sicuro per i thread. – smparkes

+0

Vedi anche: http://stackoverflow.com/questions/1999122/how-to-define-threadsafe – ergosys

+0

Non proprio un dupe, ma correlati: http://stackoverflow.com/questions/1099513/threadsafe-vector-class- per-c – ergosys

risposta

44

Lo standard C++ garantisce determinate filettature per tutte le classi della libreria C++ standard. Queste garanzie potrebbero non essere come ci si aspetterebbe che fossero, ma per tutte le classi di librerie C++ standard sono garantite determinate garanzie di sicurezza. Assicurati di leggere le garanzie fatte, tuttavia, poiché le garanzie di threading dei contenitori C++ standard di solito non sono allineate con ciò che vorresti che fossero. Per alcune classi diverse, solitamente più forti, vengono fatte delle garanzie e la risposta di seguito si applica specificamente ai contenitori. I contenitori hanno essenzialmente le seguenti garanzie filo di sicurezza:

  1. possono esistere più lettori contestuali dello stesso contenitore
  2. se ce n'è uno scrittore, vi saranno altri scrittori e nessun lettore

Questi in genere non sono quelli che le persone vorrebbero come garanzie di sicurezza dei thread ma sono molto ragionevoli data l'interfaccia dei contenitori standard: sono pensati per essere utilizzati in modo efficiente in assenza di thread di accesso multipli. L'aggiunta di qualsiasi tipo di blocco per i loro metodi interferirebbe con questo. Oltre a ciò, l'interfaccia dei contenitori non è realmente utile per qualsiasi forma di blocco interno: generalmente si utilizzano metodi multipli e gli accessi dipendono dal risultato degli accessi precedenti. Ad esempio, dopo aver controllato che un container non sia empty(), è possibile accedere a un elemento. Tuttavia, con il blocco interno non vi è alcuna garanzia che l'oggetto sia ancora nel contenitore quando viene effettivamente utilizzato.

Per soddisfare i requisiti che danno le garanzie di cui sopra, sarà probabilmente necessario utilizzare qualche forma di blocco esterno per i contenitori ad accesso simultaneo. Non so dei contenitori boost, ma se hanno un'interfaccia simile a quella dei container standard, sospetto che abbiano esattamente le stesse garanzie.

Le garanzie ei requisiti sono riportati in 17.6.4.10 [res.on.objects] paragrafo 1:

Il comportamento di un programma è indefinito se chiamate alle funzioni della libreria standard da diversi thread possono introdurre un data gara. Le condizioni in cui ciò può accadere sono specificate in 17.6.5.9. [Nota: la modifica di un oggetto di un tipo di libreria standard condivisa tra thread rischia di comportare un comportamento indefinito a meno che gli oggetti di quel tipo non vengano esplicitamente specificati come condivisibili senza razze di dati o l'utente fornisca un meccanismo di blocco. -endnote]

... e 17.6.5.9 [res.on.data.races]. Questa sezione descrive in dettaglio la descrizione più informale nel no.

+0

Si chiama reentrancy :) – vines

+2

Sarebbe [reentrancy] (http://en.wikipedia.org/wiki/Reentrancy_%28computing%29) se fosse solo funzione. Tuttavia, ci sono oggetti coinvolti che sono garantiti per non essere modificati dalle operazioni di lettura. Inoltre, la rientranza si riferisce alla funzione di essere richiamabile in modo ricorsivo in programmi a thread singolo. –

+0

Per "lettore" e "scrittore", si sta parlando della struttura del contenitore e non si scrive sugli oggetti all'interno, corretto? Ad esempio, la scrittura su 3 diversi elementi vettoriali e la lettura da un quarto da altri dieci thread, saranno consentiti tutti allo stesso tempo, a condizione che nessuno inserisca o rimuova elementi. Le regole di validità degli iteratori sembrano rilevanti qui. –

25

Ho più thread contemporaneamente chiamando push_back() su un oggetto condiviso di std :: vector. Std :: vector thread safe?

Questo è non sicuro.

Oppure devo implementare personalmente il meccanismo per renderlo sicuro?

Sì.

Voglio evitare di eseguire lavori di "blocco e liberazione" extra perché sono un utente di libreria piuttosto che un designer di libreria. Spero di cercare soluzioni thread-safe esistenti per il vettore.

Bene, l'interfaccia del vettore non è ottimale per l'uso simultaneo. Va bene se il client ha accesso a un blocco, ma per l'interfaccia per il blocco astratto per ogni operazione - no. In effetti, l'interfaccia vettoriale non può garantire la sicurezza del thread senza un blocco esterno (presupponendo che siano necessarie operazioni anche mutanti).

Che ne dici di boost :: vector, che è stato introdotto di recente da boost 1.48.0 in poi. È thread-safe?

Documenti Stato:

//! boost::container::vector is similar to std::vector but it's compatible 
//! with shared memory and memory mapped files. 
8

ho più thread chiamando contemporaneamente push_back() su un oggetto condiviso di std :: vector. ... Spero di cercare soluzioni thread-safe esistenti per il vettore.

Dai un'occhiata a concurrent_vector in Intel's TBB. A rigor di termini, è molto diverso da std::vector internamente e non è completamente compatibile con API, ma potrebbe comunque essere adatto. Potresti trovare alcuni dettagli del suo design e funzionalità in the blogs of TBB developers.