ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Вторник
21 января
1486716 Топик полностью
Nikolay_Po (26.12.2024 14:20, просмотров: 152) ответил mse homjak на ХЗ, конешно, но, каг-то неубедительно.
Я как-то озаботился, пару раз посидел и глубоко подумал. И всё понял. У меня никаких разногласий с компиляторами насчёт volatile нет. Код большого конечного автомата, что я правил, на 6000 строк (ну, так было удобно его автору), содержит всего штук 5 таких переменных - когда обращается напрямую к данным, обновляемым в прерываниях. 

Остальное волатильное сделано через геттеры/сеттеры, обращающиеся к внешним volatile-источникам с квалификатором volatile и необходимой блокировкой прерываний, если доступ не атомарен. Большинство же переменных - обычные и прекрасно оптимизируются GCC с ключами -O3 -flto=auto. И всё работает как надо.


Вам просто нужно осмыслить, где границы контекста и какие данные меняются вне его. И тогда вы просто будете понимать и знать, какую переменную нужно объявить volatile и почему. И не будете объявлять зря.

Например, у вас куча файлов исходного кода. Функции, внешние переменные. Ничего страшного - если ваш код вызывает функцию из другого листа - оно всё равно в контексте. Если выполнение вашего контекста прерывается (прерыванием аппаратуры или планировщиком ОСРВ, например) и это прерывание не меняет данных, обрабатываемых в этом контексте, то всё будет работать стандартно. Объявлять источники данных как volatile не нужно. Но если в текущем контексте вы обрабатываете данные, которые могут меняться в любом из возможных прерываний текущего кода, текущего контекста и вы эти прерывания не контролируете (не можете запретить или, наоборот, хотите получать изменения), то источник данных, меняемый в прерывании, вы обязаны объявить как volatile.

Даже массивы. Если вы меняли содержимое массива в прерывании, обновление, скорее всего, будет произведено - доступ к массиву оптимизируется меньше. Но следует объявить массив volatile - чтобы указатель на данные (в том числе и по индексу) имел соответствующий квалификатор и оптимизация не убрала принудительное обновление.


Любой код, который вызывается иначе, чем по цепочке вызовов из main(), для main() будет вне контекста. В частности, это любые аппаратные или программные прерывания.

Для кода внутри прерываний, в некоторых случаях, так же нужно объявлять источники данных как volatile, если они меняются в main() или в других прерываниях. В блоке кода, который не вызван как функция из main(), а запущен аппаратно как прерывание, обычная внешняя переменная будет прочитана в первый раз, потому, что её содержимое не известно на момент входа в контекст. Однако же далее по ходу выполнения, если требуется уточнить/подтвердить значение этой переменной, компилятор оптимизирует (удалит) повторное обращение, если переменная не была объявлена volatile. Так же, в коде прерывания, переменную нужно объявить volatile, если она была определена в этом контексте, а меняется - в других. В противном случае, компилятор увидит присвоение переменной исходного значения в коде прерывания и никогда не обновит, так как не видит изменений в пределах контекста.