2009-09-01 14 views
30

Ho una domanda sulla sicurezza del thread di std :: set.Il file C++ std :: set thread-safe?

Per quanto ne so posso scorrere su un set e aggiungere/cancellare membri e ciò non invalida gli iteratori.

Ma consideriamo seguente scenario:

  • filo 'A' itera su una serie di shared_ptr < tipo>
  • filo 'B', aggiunge di tanto in tanto gli elementi a questo insieme.

Ho sperimentato segfaults mentre il programma è in esecuzione e non sono sicuro del perché questo accada. La mancanza di sicurezza del filo è la causa?

risposta

9

Nessuno dei contenitori STL è thread-safe, quindi non lo è in particolare std::set.

Nel tuo caso, il problema non è nemmeno la sicurezza del thread, tuttavia: basta condividere un oggetto su più thread (fine) e modificarlo in un thread (bene pure). Ma come hai già detto, la modifica del contenitore invalida i suoi iteratori. Se ciò accade nello stesso thread o in un thread diverso non ha conseguenze poiché è ancora lo stesso contenitore.

D'oh! §23.1.2.8 afferma che l'inserimento non invalida gli iteratori.

+9

aggiornamento di un set non invalida gli iteratori ..... –

+0

In realtà, lo standard afferma che l'aggiunta o l'eliminazione da un oggetto std :: set non invalida nessuno dei suoi iteratori (con gli iteratori che puntano a un oggetto su essere cancellato essendo l'ovvia eccezione). – suszterpatt

+0

Grazie per il commento, l'ho completamente distrutto. Anche se devo dire, dal punto di vista di un implementatore questo è un requisito davvero strano. –

26

STL non ha un supporto thread incorporato, quindi sarà necessario estendere il codice STL con i propri meccanismi di sincronizzazione per utilizzare STL in un ambiente con multithreading.

ad esempio esaminare qui: link text

Da set è una classe contenitore MSDN ha seguito da dire sulla sicurezza filo dei contenitori.

Un singolo oggetto è thread-safe per la lettura da più thread. Ad esempio, dato un oggetto A, è sicuro leggere A dal thread 1 e dal thread 2 contemporaneamente.

Se un singolo oggetto viene scritto da un thread, tutte le letture e le scritture su quell'oggetto sullo stesso o su altri thread devono essere protette. Ad esempio, dato un oggetto A, se il thread 1 sta scrivendo su A, il thread 2 deve essere impedito dalla lettura o scrittura in A.

È sicuro leggere e scrivere su un'istanza di un tipo anche se un altro thread sta leggendo o scrivendo su un'istanza diversa dello stesso tipo. Ad esempio, dati gli oggetti A e B dello stesso tipo, è sicuro se A viene scritto nella discussione 1 e B viene letto nella discussione 2.

+8

In realtà, troverai più facile creare una classe thread-safe che contenga un file std :: set invece di estendere il set stesso. MENO meno lavoro. – Kieveli

+4

@Kieveli +1, ma è necessario fare attenzione a non fornire backdoor nel set (restituzione degli iteratori di set) e ciò può implicare la necessità di scrivere il proprio insieme di iteratori sopra gli iteratori dell'insieme in modo che gli incrementi/decrementi siano thread-safe . Né l'implementazione di un set sicuro né un wrapper sono attività semplici ... –

+0

È possibile fornire il collegamento alla citazione MSDN? NEVERMIND: http://msdn.microsoft.com/en-us/library/c9ceah3b(v=VS.100).aspx –

19

La documentazione STL di Dinkumware contiene il paragrafo seguente su tale argomento. È probabilmente (come indicato nel testo) valido per la maggior parte delle implementazioni.

Per gli oggetti contenitore definiti nel la libreria standard C++, come STL contenitori e oggetti di template classe basic_string, questo implementazione segue ampiamente pratiche adottate enunciati per SGI STL:

Più thread possono leggere tranquillamente lo stesso oggetto contenitore. (Ci sono nunprotected sottoggetti mutabili all'interno un oggetto contenitore.)

Due fili possono manipolare oggetti sicuro contenitore differente dello stesso tipo. (Non ci sono protetti oggetti statici condivisi all'interno di un tipo di contenitore.)

È necessario impedire l'accesso simultaneo ad un contenitore oggetto se almeno un filo è modificare l'oggetto. (I ovvie primitive di sincronizzazione, come quelle nella libreria Dinkum Fili, non saranno sovvertiti dall'oggetto contenitore .)

Pertanto, non viene fatto alcun tentativo per garantire che le operazioni atomiche sul contenitore oggetti sono filo sicuro; ma è abbastanza facile da rendere gli oggetti condivisi che sono thread-safe al livello appropriato di granularità .

1

Semplice spiegazione: se il thread A sta spostando gli iteratori attraverso il contenitore, sta esaminando i componenti interni del contenitore. Se il thread B modifica il contenitore (anche un'operazione che non annulla l'iteratore che A ha), il thread A può essere in guai perché B sta ingannando con gli interni del contenitore, possibilmente avendo in uno stato (temporaneamente) non valido. Ciò causa arresti anomali nella thread A.

Il problema NON sono gli iteratori stessi. Quando hanno bisogno delle strutture dati del container per trovare la posizione in cui ti trovi nei guai.

Semplice come quello.

0

Sì. Un modo per gestire questa situazione è che ogni thread blocchi un mutex condiviso prima di accedere allo stesso oggetto impostato. Assicurati di utilizzare le tecniche RAII per bloccare e sbloccare il mutex.

0

L'esecuzione di un inserimento può causare la riallocazione della memoria sottostante del vettore mentre l'iteratore può ancora puntare all'indirizzo di memoria precedente (ma non valido), causando un errore di segmento.