è usato per fare un valore sarà letto/scritto interamente
Questa è solo una piccola parte dell'atomicità. Al suo centro significa "non interrompibile", un'istruzione su un processore i cui effetti collaterali non possono essere intercalati con un'altra istruzione. In base alla progettazione, un aggiornamento della memoria è atomico quando può essere eseguito con un singolo ciclo del bus di memoria. Il che richiede che l'indirizzo della posizione di memoria sia allineato allo in modo che un singolo ciclo possa aggiornarlo. Un accesso non allineato richiede lavoro extra, parte dei byte scritti da un ciclo e parte da un altro. Ora non è più ininterrotto.
Ottenere gli aggiornamenti allineati è piuttosto semplice, è una garanzia fornita dal compilatore. O, più in generale, dal modello di memoria implementato dal compilatore. Che semplicemente sceglie gli indirizzi di memoria allineati, a volte lasciando intenzionalmente spazi vuoti inutilizzati di pochi byte per allineare la prossima variabile. Un aggiornamento a una variabile più grande della dimensione nativa del processore non può mai essere atomico.
Ma molto più importanti sono il tipo di istruzioni del processore necessarie per eseguire il threading. Ogni processore implementa una variante di CAS instruction, confronta-e-swap. È l'istruzione atomica di base necessaria per implementare la sincronizzazione. Le primitive di sincronizzazione di livello più elevato, come i monitor (cioè le variabili di condizione), i mutex, i segnali, le sezioni critiche ei semafori sono tutti costruiti su quell'istruzione principale.
Questo è il minimo, un processore di solito ne fornisce di più per rendere semplici le operazioni atomiche. Come l'incremento di una variabile, al suo interno un'operazione interrompibile poiché richiede un'operazione di lettura-modifica-scrittura. Avere bisogno di essere atomici è molto comune, la maggior parte dei programmi C++ si affida ad essa per implementare il conteggio dei riferimenti.
volatilità non garantisce la sicurezza del filo affatto
non lo fa. È un attributo che risale a tempi molto più semplici, quando le macchine avevano solo un singolo processore. Riguarda solo la generazione del codice, in particolare il modo in cui un ottimizzatore di codice tenta di eliminare gli accessi alla memoria e usa invece una copia del valore in un registro del processore. Fa una grande, grande differenza per la velocità di esecuzione del codice, la lettura di un valore da un registro è facilmente 3 volte più veloce di doverlo leggere dalla memoria.
L'applicazione volatile garantisce che il programma di ottimizzazione del codice non consideri il valore nel registro accurato e lo costringa a leggere nuovamente la memoria. Importa solo sul tipo di valori di memoria che non sono stabili da soli, dispositivi che espongono i loro registri attraverso I/O mappati in memoria. E 'stato pesantemente abusato da quel significato fondamentale per cercare di mettere la semantica sui processori con un modello di memoria debole, mentre Itanium è l'esempio più eclatante. Cosa si ottiene con volatile oggi dipende fortemente dallo specifico compilatore e runtime che si utilizza. Non utilizzarlo mai per la sicurezza del thread, utilizzare sempre una primitiva di sincronizzazione.
semplicemente essere atomica/volatile è thread-safe
programmazione sarebbe molto più semplice se fosse vero. Le operazioni atomiche coprono solo le operazioni molto semplici, un vero programma spesso ha bisogno di mantenere un intero oggetto thread-safe. Avere tutti i suoi membri aggiornati atomicamente e non esporre mai una vista dell'oggetto che è parzialmente aggiornata. Qualcosa di semplice come l'iterazione di una lista è un esempio fondamentale, non è possibile avere un altro thread che modifichi l'elenco mentre si guardano i suoi elementi. Questo è il momento in cui devi raggiungere le primitive di sincronizzazione di livello superiore, il tipo che può bloccare il codice fino a che non è sicuro procedere.
I programmi reali spesso soffrono di questa necessità di sincronizzazione e presentano il comportamento Amdahls' law. In altre parole, l'aggiunta di un thread aggiuntivo non rende il programma più veloce. A volte in realtà lo rende più lento. Chiunque trovi una trappola per topi migliore per questo è un Nobel garantito, stiamo ancora aspettando.
'volatile' indica solo una cosa: non ottimizzare gli accessi ripetuti a una variabile. Non pone alcun vincolo sull'atomicità o sul riordino delle operazioni o sulla coerenza della cache. –