Che cos'è? Stavo leggendo STL effettivo e ci siamo imbattuti in esso. Ho anche cercato su Google, ma non ho potuto ottenere alcuna informazione utile.
Che cos'è? Stavo leggendo STL effettivo e ci siamo imbattuti in esso. Ho anche cercato su Google, ma non ho potuto ottenere alcuna informazione utile.
In sostanza, molte cose possono andare storte in un ambiente multi-thread (riordino delle istruzioni, oggetti parzialmente costruiti, stessa variabile con valori diversi in thread diversi a causa della memorizzazione nella cache a livello della CPU ecc.).
Mi piace la definizione data da Concorrenza Java in pratica :
A [portion of code] is thread-safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code.
Con correttamente significano che il programma si comporta in conformità con le sue specifiche.
Esempio di contrived
Immagina di implementare un contatore. Si potrebbe dire che si comporta correttamente se:
counter.next()
non restituisce mai un valore che è già stato restituito in precedenza (non assumiamo overflow ecc. per semplicità) Un contatore thread-safe si comporterebbe secondo queste regole indipendentemente dal numero di thread che lo accedono contemporaneamente (il che in genere non sarebbe il caso di un'implementazione ingenua).
La sicurezza del thread è un termine generico che si riferisce a evitare problemi di R / W e di sincronizzazione, in presenza di più thread che accedono agli stessi dati.
In pratica, quando due (o più) thread accedono agli stessi dati e almeno uno modifica i dati, l'altro thread può raggiungere uno stato incoerente o leggere dati corrotti (il codice non è "thread-safe") ).
Per evitare ciò, esiste un intero set di tecniche in C ++ (varie implementazioni mutex, eventi, "pattern di controllo a doppio blocco", std :: atomic e molto altro).
Per un semplice esempio, prendi in considerazione:
void an_object::member_function()
{
if (p != nullptr) // 1
{
delete p; // 2
p = new int(10);// 3
}
int q = *p; // 4
}
Considera due thread che eseguono an_object :: member_function per la stessa istanza di oggetto, dove p e q appartengono a an_object.
Ecco alcuni scenari:
scenario 1:
il thread 1 esegue la riga 1
il thread 2 esegue la riga 1
il thread 1 esegue la riga 2
il thread 2 esegue la riga 2 e si ha una doppia eliminazione (seguito da un comportamento non definito)
scenario 2:
il thread 1 esegue la riga 1, 2 e 3
il thread 2 esegue la riga 1 e 2
il thread 1 esegue la riga 4, utilizzando un indirizzo appena eliminato dal thread 2 (e il comportamento non definito viene visualizzato nuovamente).
Ci sono molti altri scenari che portano a un comportamento indefinito con queste quattro linee di codice.
La sicurezza del filo è stata meglio solidificata nella mia mente quando ci ho pensato in termini di un ORM.
Quando il tuo ORM va a salvare tutti gli oggetti nel database, non è thread-safe.
Perché? Bene, parte della responsabilità di un ORM è di tracciare un sacco di stato interno (al fine di capire cosa fare quando arriva il momento di fare effettivamente persistenza). Se sei a metà strada tra tutte le routine di gestione dello stato per una chiamata a "Salva" e inizi a eseguire una routine secondaria "Salva", cosa accadrà diamine ? Sarai deluso dai risultati se speri che succedano cose belle.
Questo è un buon esempio perché la sicurezza dei thread riguarda la possibilità o meno che lo stato degli oggetti "sopravviva" a una seconda voce di una routine.
(Anche perché chiunque crei un repository statico per la propria app Web viene vergognato senza sosta.)
Qualcosa è thread-safe se può essere utilizzato da più thread senza malfunzionamenti.
Leggi altre domande sui tag language-agnostic multithreading