Słowo kluczowe volatile informuje kompilator, że zmienna może zmieniać się w sposób nieoczekiwany dla kompilatora (na przykład przez sprzęt, inną nitkę lub obsługę przerwań) i zabrania buforowania jej wartości oraz optymalizacji dostępu do niej.
Zastosowanie:
volatile nie gwarantuje atomowości ani synchronizacji!).volatile int flag = 0; void handler() { flag = 1; // obsługa przerwania } void loop() { while (!flag) { // czekamy na zdarzenie } // ... }
Bez volatile kompilator mógłby zastąpić pętlę nieskończoną (nie odczytując flagi z pamięci), z volatile zmienna jest odczytywana za każdym razem z pamięci.
Czy wystarczy użyć volatile do poprawnej wymiany informacji między wątkami?
Częstym błędem jest sądzenie, że volatile zapewnia synchronizację pamięci między wątkami i sprawia, że operacje są atomowe.
Poprawna odpowiedź:
volatile nie chroni przed wyścigami danych w wielowątkowym środowisku i nie zapewnia barier pamięci: jedynie informuje kompilator, aby nie optymalizował dostępu. Aby mieć gwarancję poprawności, należy używać prymitywów synchronizacji (mutex, operacje atomic itd.).
// To nie jest bezpieczne! volatile int ready = 0; void thread1() { data = 123; // zapis danych ready = 1; // sygnał dla innej nitki } void thread2() { while (!ready); // oczekiwanie na zdarzenie printf("data = %d\n", data); // możliwe, że data jeszcze nie jest zaktualizowane! }
Historia