Het sleutelwoord volatile geeft de compiler aan dat een variabele onverwachts kan veranderen voor de compiler (bijvoorbeeld door hardware, een andere thread of een interrupt handler), en voorkomt dat de waarde ervan in cache wordt opgeslagen of dat toegang tot deze variabele wordt geoptimaliseerd.
Toepassing:
volatile garandeert geen atomiciteit of synchronisatie!).volatile int flag = 0; void handler() { flag = 1; // interrupt handler } void loop() { while (!flag) { // wacht op een gebeurtenis } // ... }
Zonder volatile zou de compiler de lus als oneindig kunnen vervangen (flag niet uit het geheugen lezen), met volatile wordt de variabele elke keer uit het geheugen gelezen.
Is het voldoende om volatile te gebruiken voor correcte informatie-uitwisseling tussen threads?
Een veelvoorkomende fout is om aan te nemen dat volatile geheugen-synchronisatie tussen threads biedt en operaties atomic maakt.
Juiste antwoord:
volatile beschermt niet tegen dataraces in een multithreading omgeving en biedt geen geheugenbarrières: het vertelt alleen de compiler om de toegang niet te optimaliseren. Voor gegarandeerde correctheid moeten synchronisatieprimitieven (mutex, atomic operaties, enz.) worden gebruikt.
// Dit is niet veilig! volatile int ready = 0; void thread1() { data = 123; // schrijf gegevens ready = 1; // signaal voor een andere thread } void thread2() { while (!ready); // wacht op gebeurtenis printf("data = %d\n", data); // mogelijk is data nog niet bijgewerkt! }
Geschiedenis
Fout bij het werken met hardware registers: de waarde werd gelezen/schreven zonder volatile, en de compiler optimaliseerde de toegang, waardoor nieuwe waarden van de registers volledig werden genegeerd — sommige opdrachten werkten niet.