Ce face volatile
Compilatorul optimizează: dacă vede că o variabilă nu se schimbă într-o buclă, o poate citi o singură dată. volatile interzice asta: fiecare citire și fiecare scriere din cod se face cu adevărat în memorie.
Folosirile corecte sunt puține: registre hardware la microcontrolere (valoarea se schimbă singură), variabile modificate dintr-un handler de semnal (volatile std::sig_atomic_t) și câteva cazuri de măsurare a performanței.
volatile nu face o variabilă sigură între fire de execuție (thread-uri). Pentru asta există std::atomic și std::mutex. Din C++20, operații ca ++ sau += pe variabile volatile sunt considerate învechite (deprecated).
Exemple
Exemplul 1: Variabilă modificată de un handler de semnal
std::raise trimite programului semnalul SIGINT (același ca la Ctrl+C), iar handler-ul setează variabila. Tipul volatile std::sig_atomic_t este cel garantat sigur pentru acest caz.
#include <csignal>
#include <print>
volatile std::sig_atomic_t oprire_ceruta = 0;
void la_semnal(int) {
oprire_ceruta = 1;
}
int main() {
std::signal(SIGINT, la_semnal);
std::println("Înainte: {}", static_cast<int>(oprire_ceruta));
std::raise(SIGINT);
std::println("După semnal: {}", static_cast<int>(oprire_ceruta));
if (oprire_ceruta) {
std::println("Programul se oprește curat.");
}
}
Rezultat
Înainte: 0
După semnal: 1
Programul se oprește curat.
Exemplul 2: Citiri și scrieri care nu sunt eliminate
Fără volatile, compilatorul ar putea înlocui cele 1000 de scrieri cu una singură. Cu volatile, fiecare scriere are loc (util, de exemplu, pentru un registru hardware).
#include <print>
int main() {
volatile int registru = 0;
for (int i = 0; i < 1000; i = i + 1) {
registru = i;
}
int ultima = registru;
std::println("Ultima valoare scrisă: {}", ultima);
}
Rezultat
Ultima valoare scrisă: 999
Greșeli frecvente
- Folosești
volatile bool gataca să comunici între două fire de execuție. Nu este suficient (nu garantează ordinea operațiilor și nici atomicitatea); foloseștestd::atomic<bool>. - Scrii
contor++pe o variabilăvolatile. În C++20 primești avertisment de învechire; scrie explicitcontor = contor + 1și gândește-te dacă îți trebuie de faptstd::atomic.
Comenzi înrudite
const: Marchează o valoare care nu mai poate fi modificată după inițializare; compilatorul oprește orice încercare de schimbare.asm: Inserează instrucțiuni în limbaj de asamblare direct în codul C++; sintaxa și instrucțiunile depind de compilator și de procesor.thread_local: Fiecare fir de execuție (thread) primește propria copie a variabilei, creată când pornește firul și distrusă la final.std::atomic: Variabilă care poate fi citită și modificată sigur de mai multe fire, fără mutex.