La parola chiave volatile informa il compilatore che una variabile può cambiare in modo imprevisto per il compilatore (ad esempio, da hardware, un altro thread o un gestore di interruzioni), e impedisce la memorizzazione nella cache del suo valore o l'ottimizzazione degli accessi ad essa.
Usato per:
volatile non garantisce atomicità o sincronizzazione!).volatile int flag = 0; void handler() { flag = 1; // gestore di interruzione } void loop() { while (!flag) { // aspetta l'evento } // ... }
Senza volatile, il compilatore potrebbe sostituire il ciclo con uno infinito (non leggendo flag dalla memoria), con volatile, la variabile viene letta ogni volta dalla memoria.
È sufficiente usare volatile per un corretto scambio di informazioni tra thread?
Un errore comune è pensare che volatile garantisca la sincronizzazione della memoria tra thread e renda le operazioni atomiche.
Risposta corretta:
volatile non protegge dagli accessi concorrenti in un ambiente multithread e non fornisce barriere di memoria: essa informa solo il compilatore di non ottimizzare l'accesso. Per una correttezza garantita è necessario utilizzare primitiva di sincronizzazione (mutex, operazioni atomic, ecc.).
// Questo non è sicuro! volatile int ready = 0; void thread1() { data = 123; // scrittura dei dati ready = 1; // segnale per un altro thread } void thread2() { while (!ready); // attesa dell'evento printf("data = %d ", data); // potrebbe essere che data non sia ancora aggiornata! }
Storia