2012-03-01 13 views
12

Sono consapevole del fatto che i contenitori della libreria standard non sono thread-safe. Con ciò pensavo che un contenitore, ad esempio di tipo std::list, non fosse accessibile da più di un thread contemporaneamente (alcuni dei quali potrebbero modificare il contenitore). Ma ora sembra che ci sia più di quello che incontra l'occhio; qualcosa di più sottile, qualcosa di non così ovvio, almeno per me.contenitori standard come variabili locali nell'applicazione multi-thread

Ad esempio, si consideri questa funzione che accetta il primo argomento per valore:

void log(std::string msg, severity s, /*...*/) 
{ 
    return; //no code! 
} 

È questo thread-safe?

In un primo momento, sembra che sia thread-safe, in quanto il corpo della funzione non accede alle risorse modificate , quindi thread-safe. A pensarci bene, mi viene da pensare che quando si invoca una funzione di questo tipo, verrà creato un oggetto di tipo std::string, che è il primo argomento, e penso che la costruzione di questo oggetto non sia thread-safe, poiché utilizza internamente std::allocator , che credo non sia sicuro per i thread. Quindi invocare una tale funzione non è sicuro per i thread. Ma se è corretto, allora che ne pensi:

void f() 
{ 
    std::string msg = "message"; //is it thread-safe? it doesn't seem so! 
} 

Sto andando giusto? È possibile utilizzare std::string (o qualsiasi contenitore che utilizza internamente std::allocator) nel programma a più thread?

Sto specificatamente parlando di contenitori come variabili locali, al contrario di oggetti condivisi.

Ho cercato su Google e ho trovato molti dubbi simili, senza una risposta concreta. Affronto problema simile come il suo:

Si prega di considerare C++ 03 e C++ 11, entrambe le cose.

+0

Nawaz: sai di quale implementazione del C++ si tratta qui: http://www.sgi.com/tech/stl/Allocators.html Si afferma che l'allocatore predefinito è thread-safe. – Sid

+0

@ Sid: non è una libreria standard; supportano molte cose che stdlib non ha. – Nawaz

+0

Ok, mi dispiace per la distrazione. – Sid

risposta

7

In C++ 11, std::allocator è thread-safe. Dalla sua definizione:

20.6.9.1/6: Nota: l'archiviazione è ottenuto chiamando ::operator new(std::size_t)

e dalla definizione di ::operator new:

18.6.1.4: Le versioni di libreria di operator new e operator delete, versioni di sostituzione utente di globale operator new e operator delete e le funzioni di libreria standard C on calloc, malloc, realloc e free devono non introdurre dati razze (1.10) come risultato di chiamate concorrenti da thread diversi.

C++ 03 non aveva alcun concetto di thread, quindi qualsiasi sicurezza del thread era specifica dell'implementazione; dovresti fare riferimento alla documentazione della tua implementazione per vedere quali garanzie ha offerto, se ce ne sono.Dal momento che stai usando l'implementazione di Microsoft, this page dice che è sicuro scrivere su più oggetti contenitore della stessa classe da molti thread, il che implica che std::allocator è thread-safe.

+0

È C++ 11. Che dire di C++ 03? C++ 03 non aveva alcun concetto di multithreading. – Nawaz

+0

Beh, ho cercato C++ 03, e sembra che l'allocatore di C++ 03 non sia thread-safe. – Nawaz

+0

@Nawaz: Infatti, C++ 03 non dice nulla sulla sicurezza dei thread, quindi dovrai fare riferimento alla documentazione del tuo compilatore/libreria. –

5

In C++ 11 questo sarà trattato per l'allocatore predefinito in:

20.6.9.1 membri allocatore [allocator.members]

Fatta eccezione per il distruttore, funzioni membro della allocatore predefinito non introduce le corse di dati (1.10) come risultato di chiamate contemporanee a quelle funzioni membro da thread diversi. Le chiamate a queste funzioni che allocano o deallocano una determinata unità di memoria devono avvenire in un unico ordine totale e ciascuna di tali chiamate di deallocazione deve avvenire prima dell'allocazione successiva (se presente) in questo ordine.

Qualsiasi allocatore fornito dall'utente deve rispettare gli stessi vincoli se dovesse essere utilizzato su thread diversi.

Naturalmente, per le versioni precedenti dello standard, non si parla di questo poiché non hanno parlato del multithreading. Se un'implementazione dovesse supportare il multithreading (come molti o più), sarebbe responsabile di occuparsi di tali problemi. Simile al modo in cui le implementazioni forniscono una sicurezza thread-thread malloc() (e altre funzioni di libreria) per C e C++ anche se gli standard precedenti a molto recentemente non hanno detto nulla a riguardo.

3

Come forse avete già capito, non ci sarà una risposta facile, sì o no. Tuttavia, penso che questo può aiutare:

http://www.cs.huji.ac.il/~etsman/Docs/gcc-3.4-base/libstdc++/html/faq/index.html#5_6

cito testualmente:

5,6 Is libstdC++ - v3 thread-safe?

libstdC++ - v3 si sforza di essere thread-safe quando sono soddisfatte tutte le seguenti condizioni: libc

del sistema è di per sé thread-safe, gcc -v riporta un modello di thread diverso da 'single', [solo pre-3.3] esiste una implementazione non generica di atomicity.h per l'architettura in questione.

+0

Riguarda un'implementazione particolare della lib in un compilatore molto vecchio ... 1 –

+0

@ DavidRodríguez-dribeas Penso che la maggior parte delle risposte che troveremo a questa domanda dipenderanno da quale compilatore/versione C++ e da quale implementazione malloc è in uso. – Sid

2

Quando un std::string viene copiato durante la chiamata al log, l'allocatore può essere thread-safe (obbligatoria in C++ 11), ma la copia stessa non è. Quindi, se c'è un altro thread che modifica la stringa sorgente mentre la copia è in corso, questa non è thread-safe.

Si può terminare con metà della stringa come era prima della mutazione e un'altra metà dopo, o può persino terminare l'accesso alla memoria deallocata se il thread mutante viene riallocato (ad esempio aggiungendo nuovi caratteri) o eliminato la stringa, mentre la copia stava ancora avendo luogo.


OTOH, il ...

std::string msg = "message"; 

...è thread-safe se l'allocatore è thread-safe.

+0

"* Quindi se c'è un altro thread che muta la stringa sorgente mentre la copia è in corso, questo non è sicuro. *". Questo è un problema diverso. Non ne parlo, perché in questo caso il problema sta nella lettura dell'oggetto condiviso, mentre parlo di oggetti locali. – Nawaz

+1

@Nawaz Quindi l'intero problema si riduce alla sicurezza del thread del tuo allocatore, perché questa è l'unica cosa che viene condivisa tra i thread. –

Problemi correlati