Ключевое слово volatile сообщает компилятору, что переменная может изменяться неожиданно для компилятора (например, аппаратурой, другой нитью или обработчиком прерывания), и запрещает кэшировать её значение или оптимизировать обращения к ней.
Применяется:
volatile не гарантирует атомарность или синхронизацию!).volatile int flag = 0; void handler() { flag = 1; // обработчик прерывания } void loop() { while (!flag) { // ждём события } // ... }
Без volatile компилятор мог бы заменить цикл на бесконечный (не читать flag из памяти), с volatile переменная читается каждый раз из памяти.
Достаточно ли использовать volatile для корректного обмена информацией между потоками?
Частая ошибка — считать, что volatile обеспечивает синхронизацию памяти между потоками и делает операции атомарными.
Правильный ответ:
volatile не защищает от гонок данных в многопоточном окружении и не обеспечивает барьеры памяти: она только говорит компилятору не оптимизировать обращение. Для гарантированной корректности обязательно использовать примитивы синхронизации (mutex, atomic операции и т.п.).
// Это небезопасно! volatile int ready = 0; void thread1() { data = 123; // запись данных ready = 1; // сигнал другой нити } void thread2() { while (!ready); // ожидание события printf("data = %d ", data); // возможно data ещё не обновлены! }
История