Да, volatile - это абсолютный минимум, который вам нужен. Это гарантирует, что генератор кода не будет генерировать код, который хранит переменную в регистре и всегда выполняет чтение и запись из / в память. Большинство генераторов кода могут предоставить гарантии атомарности для переменных, имеющих тот же размер, что и собственное слово ЦП, они обеспечат выравнивание адреса памяти, чтобы переменная не могла переместиться через границу строки кэша.
Это, однако, не очень сильный контракт на современные многоядерные процессоры. Volatile не обещает, что другой поток, работающий на другом ядре, сможет видеть обновления переменной. Для этого требуется барьер памяти, обычно инструкция, которая очищает кэш процессора. Если вы не предоставите барьер, поток будет продолжать работать до тех пор, пока такой сброс не произойдет естественным образом. Это в конечном итоге произойдет, планировщик потока должен предоставить один. Это может занять миллисекунды.
После того, как вы позаботились о подобных деталях, вы в конечном итоге заново изобрели условную переменную (она же событие), которая вряд ли будет быстрее, чем та, которая предоставляется библиотекой потоков. Или так же хорошо проверено. Не придумывайте свои собственные, многопоточность достаточно сложна, чтобы разобраться, вам не нужен FUD, чтобы не быть уверенным в том, что самые базовые примитивы надежны.