Не пытайтесь использовать `volatile` для синхронизации
Причина
В C++ в отличие от некоторых других языков, volatile не обеспечивает атомарность, не синхронизирует между потоками и не предотвращает переупорядочивание инструкций (ни компилятором, ни оборудованием). Это просто не имеет никакого отношения к параллелизму.
Плохой пример:
int free_slots = max_slots; // current source of memory for objects
Pool* use()
{
if (int n = free_slots--) return &pool[n];
}
Здесь у нас есть проблема: это отличный код в однопоточной программе, но если два потока выполняют это, и есть состояние гонки на free_slots, так что два потока могут получить одно и то же значение free_slots. Это (очевидно) плохая гонка данных, поэтому люди, обученные в других языках, могут попытаться исправить это вот так:
volatile int free_slots = max_slots; // current source of memory for objects
Pool* use()
{
if (int n = free_slots--) return &pool[n];
}
Это не влияет на синхронизацию: гонка данных все ещё там!
Механизм C++ для этого — atomic типы:
atomic<int> free_slots = max_slots; // current source of memory for objects
Pool* use()
{
if (int n = free_slots--) return &pool[n];
}
Теперь операция -- атомарна, а не последовательность чтение-приращение-запись, где другой поток может вмешаться между отдельными операциями.
Альтернатива
Используйте atomic типы там, где вы могли бы использовать volatile в каком-то другом языке. Используйте mutex для более сложных примеров.