C программисты часто воспринимают переменные как означающие, что переменная
может быть изменено за пределами текущего потока выполнения; как
В результате они иногда испытывают желание использовать его в коде ядра, когда
общие структуры данных используются. Другими словами, они были
известно, что летучие типы рассматриваются как своего рода легкая атомарная переменная, которая
они не. Использование volatile в коде ядра почти никогда
правильный; этот документ описывает почему.
Ключевым моментом, который необходимо понять в отношении изменчивости, является то, что ее
Цель состоит в том, чтобы подавить оптимизацию, которая почти никогда не бывает
действительно хочет сделать. В ядре нужно защищать общие данные
структуры против нежелательного одновременного доступа, который очень
другая задача. Процесс защиты от нежелательных
параллелизм также позволит избежать практически всех проблем, связанных с оптимизацией
более эффективным способом.
Как и volatile, примитивы ядра, которые делают одновременный доступ к
безопасные данные (спин-блокировки, мьютексы, барьеры памяти и т. д.) предназначены для
предотвратить нежелательную оптимизацию. Если они используются должным образом, там
не будет необходимости использовать volatile также. Если летучий все еще
необходимо, почти наверняка есть ошибка в коде где-то. В
правильно написанный код ядра, volatile может служить только для замедления
вниз.
Рассмотрим типичный блок кода ядра:
spin_lock(&the_lock);
do_something_on(&shared_data);
do_something_else_with(&shared_data);
spin_unlock(&the_lock);
Если весь код соответствует правилам блокировки, значение shared_data
не может неожиданно измениться, пока удерживается the_lock. Любой другой код
который может захотеть поиграть с этими данными, будет ожидать блокировки.
Примитивы спин-блокировки действуют как барьеры памяти - они явно
написано для этого - это означает, что доступ к данным не будет оптимизирован
через них. Таким образом, компилятор может подумать, что он знает, что будет в
shared_data, но вызов spin_lock (), так как он действует как память
барьер, заставит его забыть все, что он знает. Здесь не будет
проблемы оптимизации с доступом к этим данным.
Если бы shared_data были объявлены как volatile, блокировка все равно была бы
необходимо. Но компилятор также не сможет оптимизировать
доступ к shared_data в критическом разделе, когда мы знаем, что
никто другой не может работать с этим. Пока блокировка удерживается,
Общие_данные не являются энергозависимыми. При работе с общими данными, собственно
блокировка делает энергозависимые ненужными и потенциально опасными.
Класс энергозависимой памяти изначально предназначался для ввода-вывода с отображением в память
регистры. Внутри ядра доступ к реестру тоже должен быть
защищен блокировками, но компилятору тоже не нужен
«оптимизирующий» доступ к регистру в критической секции. Но внутри
ядро, доступ к памяти ввода / вывода всегда осуществляется через аксессор
функции; доступ к памяти ввода / вывода напрямую через указатели хмурится
на и не работает на всех архитектурах. Эти средства доступа
написано, чтобы предотвратить нежелательную оптимизацию, поэтому, опять же, volatile
нет необходимости.
Другая ситуация, когда можно испытать искушение использовать volatile, это когда
процессор занят ожиданием значения переменной. Право
Способ выполнения занятого ожидания:
while (my_variable != what_i_want)
cpu_relax();
Вызов cpu_relax () может снизить энергопотребление процессора или привести к
двухпроцессорный гиперзаход; это также случается, чтобы служить памятью
барьер, так что, опять же, изменчиво не нужно. Конечно,
Ожидание «занято» - это, как правило, антиобщественный акт.
Есть еще несколько редких ситуаций, в которых изменчивость имеет смысл в
ядро:
Вышеупомянутые функции доступа могут использовать volatile на
архитектуры, в которых прямой доступ к памяти ввода-вывода работает. По существу,
каждый вызов доступа становится небольшим критическим разделом сам по себе игарантирует, что доступ происходит в соответствии с ожиданиями программиста.
Встроенный ассемблерный код, который изменяет память, но не имеет другого
видимые побочные эффекты, риски удаляются GCC. Добавление летучих
операторы "ключевое слово в asm" предотвратят это удаление.
Переменная jiffies отличается тем, что может иметь другое значение
каждый раз, когда на него ссылаются, но его можно прочитать без каких-либо специальных
замок. Таким образом, jiffies может быть изменчивым, но добавление других
переменные этого типа решительно осуждаются. Jiffies считается
быть «глупым наследием» проблемой (слова Линуса) в этом отношении; исправить это
будет больше проблем, чем стоит.
Указатели на структуры данных в когерентной памяти, которые могут быть изменены
Устройства ввода / вывода иногда могут быть законно изменчивыми. Кольцевой буфер
используется сетевым адаптером, где этот адаптер меняет указатели на
указать, какие дескрипторы были обработаны, является примером этого
тип ситуации.
Для большей части кода не применимо ни одно из приведенных выше обоснований для volatile.
В результате использование volatile, вероятно, будет рассматриваться как ошибка и
принесет дополнительную проверку кода. Разработчики, которые
соблазн использовать летучий следует сделать шаг назад и подумать о том, что
они действительно пытаются достичь.