Почему пометить аргумент функции как volatile

в настоящее время я читаю 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 используется в определении типа, оно указывает компилятору, как он должен обрабатывать переменную. В первую очередь это говорит компилятору, что значение переменная может изменяться в любое время в результате действий, внешних по отношению к программе или текущей линии выполнения. (источник)

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

5 ответов


volatile BufferDesc *buf означает, что данные, которые buf указывает на является изменчивым, не то, что указатель, содержащийся buf изменчив. (Это было бы BufferDesc * volatile buf.)

С страница, которую вы связали с:

С другой стороны, если у вас есть переменная указателя, где сам адрес был изменчив, но указанная память не была, тогда у нас есть:

int * volatile x;

обновление: Извините, я пропустил эту часть ваш вопрос:

так почему некоторые аргументы функции объявлены как volatile?

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


Я не ожидаю, что DMA изменит местоположение указателя.

Не местоположение, но, возможно, содержимое. И это именно то, о чем идет речь...


реализация баз данных не зависит от буферов и кэшей ОС при доступе к файлам. Они предпочитают реализовывать собственную систему кэша и получите прямой доступ к файлу на физическом диске, для проблем с надежностью: данные должны быть сброшены на физический диск. (Они используют параметр O_DIRECT для прямого доступа к физическому диску.)

3 функции, которые вы показываете нам, заставляют меня думать об асинхронной обработке данных, поступающих с диска. (StartBufferIO(), TerminatedBufferIO() и так далее). Честно говоря, я не уверен, в чем их цель, но на основе того, что я знаю о реализации баз данных и именах этих функций, я бы сказал, что содержимое буфера может быть изменено самим "диском" с данными из файла на диске (или любом другом устройстве), и поэтому его нужно flaged как volatile.

эта гипотеза присоединяется к вашей обычной интерпретации того, что volatile ключевое слово обычно используется для: устройства водители.


DMA не единственная причина использовать "volatile". Это также полезно для многопоточных приложений и общей памяти, где другой поток может изменить память, на которую ссылается этот код. Я уверен, что PostgreSql многопоточен, поэтому это вероятная причина, по которой здесь используется volatile.


одна вещь, которую компилятор обычно делает при оптимизации, - это удаление мертвого кода, поэтому, если вы выполняете некоторые операции с переменной, которую он никогда не читал, и ее результат бесполезен, компилятор, вероятно, просто удалит его, а также удалит остальные операции, которые влияют на него. Это поведение может быть очень раздражающим, когда вы отлаживаете код или выполняете какие-то benchamrks. Если вы объявляете переменную volatile, вы предупреждаете компилятор, что она может использоваться внешними библиотеками или программы, среди других последствий ключевое слово может иметь. Тогда он никогда не должен рассматривать его как мертвый код.