Зачем отмечать аргумент функции как изменчивый
В настоящее время я читаю код PostgreSql. Вот выдержка из диспетчера буфера:
static void WaitIO(volatile BufferDesc *buf);
static bool StartBufferIO(volatile BufferDesc *buf, bool forInput);
static void TerminateBufferIO(volatile BufferDesc *buf, bool clear_dirty,
Я знаю, что ключевое слово volatile обычно используется для драйверов устройств и во встроенных системах. Существует объяснение ключевого слова.
Когда ключевое слово volatile используется в определении типа, оно дает указание компилятору о том, как он должен обрабатывать переменную. Прежде всего, он сообщает компилятору, что значение переменной может измениться в любое время в результате действий, внешних по отношению к программе или текущей строке выполнения. (Источник)
Итак, почему некоторые аргументы функции объявлены как изменчивые? Я не ожидаю, что DMA изменит местоположение указателя. Итак, что здесь происходит?
Ответы
Ответ 1
volatile BufferDesc *buf
означает, что данные, которые buf
указывает на значение, являются volatile, а не то, что указатель, содержащийся в buf
, является изменчивым. (Это будет BufferDesc * volatile buf
.)
От страница, с которой вы связались:
С другой стороны, если у вас есть указательная переменная, в которой сам адрес был изменчивым, но указанная память была не тогда:
int * volatile x;
Обновление: Извините, я пропустил эту часть вашего вопроса:
Итак, почему некоторые аргументы функции объявлены как volatile?
Предположительно, потому что данные, на которые он указывает, могут измениться таким образом, о которых компилятор не обязательно знал. Ключевое слово volatile
используется для предотвращения использования компилятором оптимизаций, предполагающих, что данные не изменяются, как это не известно.
Ответ 2
Я не ожидаю, что DMA изменит местоположение указателя.
Не местоположение, но, возможно, контент. И это именно то, о чем речь...
Ответ 3
Реализация баз данных не зависит от буферов ОС и кэшей при доступе к файлам. Они предпочитают реализовать свою собственную систему кэширования и получить прямой доступ к файлу на физическом диске, для проблем надежности: данные ДОЛЖНЫ быть сброшены на физический диск. (Они используют опцию O_DIRECT для прямого доступа к физическому диску.)
3 функции, которые вы показываете нам, заставляют меня думать о асинхронной обработке данных, поступающих с диска. (StartBufferIO(), TerminatedBufferIO() и т.д.). Честно говоря, я не уверен, в чем их цель, но на основе того, что я знаю о реализации баз данных и этих имен функций, я бы сказал, что содержимое буфера может быть изменено самим "диском" данными из файла на диске (или какое-либо другое устройство) и, следовательно, должен быть отброшен как volatile.
Эта гипотеза объединяет вашу обычную интерпретацию того, что обычно используется volatile: драйверы устройств.
Ответ 4
DMA - не единственная причина использования "изменчивости". Он также полезен для приложений с многопоточной и общей памятью, где другой поток может изменять память, на которую ссылается этот код. Я уверен, что PostgreSql многопоточен, поэтому это вероятная причина, по которой здесь используется volatile.
Ответ 5
Одна вещь, которую обычно выполняет компилятор при оптимизации, заключается в удалении мертвого кода, поэтому, если вы выполняете некоторые операции с переменной, которая никогда не читает ни один из ее результатов, бесполезный компилятор, вероятно, просто удалит ее, а также удалит остальные операции который влияет на нее. Такое поведение может быть очень раздражающим, когда вы отлаживаете код, и вы выполняете какие-то скамьи. Если вы объявляете изменчивой переменную, вы предупреждаете ее о том, что она может использоваться внешними библиотеками или программами, среди прочих последствий может иметься ключевое слово. Тогда он никогда не должен воспринимать его как мертвый код.