После глядя на кучу из других вопросов и их ответов , я получаю впечатление , что не существует никакого широко распространенного соглашения о том , что «летучий» ключевое слово в C означает точно.
Даже сам стандарт не достаточно ясен для того, чтобы все могли понять, что это значит .
Среди других проблем:
- Кажется, он дает разные гарантии в зависимости от вашего оборудования и от вашего компилятора.
- Это влияет на оптимизацию компилятора, но не на аппаратную оптимизацию, поэтому на усовершенствованном процессоре, который выполняет свои собственные оптимизации во время выполнения, даже не ясно, может ли компилятор предотвратить любую оптимизацию, которую вы хотите предотвратить. (Некоторые компиляторы генерируют инструкции для предотвращения некоторых аппаратных оптимизаций в некоторых системах, но это никак не стандартизировано.)
Чтобы подвести итог проблемы, кажется (после прочтения много), что «volatile» гарантирует что-то вроде: Значение будет прочитано / записано не только из / в регистр, но по крайней мере в кэш L1 ядра, в том же порядке, что чтения / записи появляются в коде. Но это кажется бесполезным, поскольку чтение / запись из / в регистр уже достаточны в том же потоке, в то время как координация с кешем L1 не гарантирует что-либо еще в отношении координации с другими потоками. Я не могу себе представить, когда это может быть важно синхронизировать только с кешем L1.
ИСПОЛЬЗОВАНИЕ 1
Единственное широко согласованное использование volatile, по-видимому, относится к старым или встроенным системам, где определенные области памяти аппаратно отображаются на функции ввода / вывода, например, бит в памяти, который управляет (напрямую, в аппаратном обеспечении) индикатором. или бит в памяти, который сообщает вам, нажата ли клавиша на клавиатуре или нет (потому что она подключена аппаратно непосредственно к клавише).
Кажется, что «use 1» не встречается в переносимом коде, цели которого включают многоядерные системы.
ИСПОЛЬЗОВАНИЕ 2
Не слишком отличается от «использования 1» память, которая может быть прочитана или записана в любое время обработчиком прерываний (который может управлять подсветкой или сохранять информацию с ключа). Но уже для этого у нас есть проблема, заключающаяся в том, что в зависимости от системы обработчик прерываний может работать на другом ядре со своим собственным кешем памяти , а «volatile» не гарантирует когерентность кеша во всех системах.
Таким образом, «использование 2», по-видимому, выходит за рамки того, что может дать «изменчивый».
ИСПОЛЬЗОВАНИЕ 3
Единственные бесспорное использование я вижу , чтобы предотвратить неправильную оптимизацию доступов с помощью различных переменных , указывающих на ту же области памяти , что компилятор не понимает та же память. Но это возможно только неоспоримо , потому что люди не говорят об этом - я видел только одно упоминание о нем. И я думал, что стандарт C уже признал, что «разные» указатели (например, разные аргументы для функции) могут указывать на один и тот же элемент или близлежащие элементы, и уже указывал, что компилятор должен создавать код, который работает даже в таких случаях. Однако я не смог быстро найти эту тему в последнем (500 страниц!) Стандарте.
Таким образом, «использовать 3», возможно, не существует вообще?
Отсюда мой вопрос:
Гарантирует ли «volatile» что-либо вообще в переносимом коде C для многоядерных систем?
РЕДАКТИРОВАТЬ - обновить
Просматривая последний стандарт , похоже, что ответ, по крайней мере, очень ограничен: да.
1. Стандарт многократно определяет специальную обработку для конкретного типа "volatile sig_atomic_t". Однако в стандарте также говорится, что использование функции сигнала в многопоточной программе приводит к неопределенному поведению. Таким образом, этот вариант использования кажется ограниченным связью между однопоточной программой и ее обработчиком сигналов.
2. Стандарт также устанавливает четкое значение для «volatile» по отношению к setjmp / longjmp. (Пример кода, где это важно, дан в других вопросах и ответах .)
Таким образом, возникает более точный вопрос:
гарантирует ли «volatile» что-либо вообще в переносимом коде C для многоядерных систем, кроме (1) разрешения однопоточной программе получать информацию от своего обработчика сигналов или (2) разрешения setjmp код для просмотра переменных, измененных между setjmp и longjmp?
Это все еще вопрос да / нет.
Если «да», было бы здорово, если бы вы могли показать пример безошибочного переносимого кода, который становится ошибочным, если опущен «volatile». Если «нет», то я предполагаю, что компилятор может игнорировать «volatile» вне этих двух очень специфических случаев для многоядерных целей.
volatile
именно того, что, я считаю, необходимо.
volatile
информирования программы о том, что она может изменяться асинхронно.