Почему POSIX mmap не возвращает изменчивую пустоту *? - PullRequest
10 голосов
/ 09 июля 2010

Mmap возвращает пустоту *, но не volatile void*. Если я использую mmap для сопоставления разделяемой памяти, то другой процесс может записывать в эту память, что означает, что два последовательных чтения из одной и той же ячейки памяти могут давать разные значения - для чего предназначена именно ситуация volatile. Так почему же он не возвращает летучую пустоту *?

Мое лучшее предположение состоит в том, что если у вас есть процесс, который пишет исключительно в сегмент совместно используемой памяти, ему не нужно смотреть на разделяемую память через изменчивые указатели, потому что он всегда будет правильно понимать, что присутствует; любая оптимизация, которую выполняет компилятор для предотвращения избыточного чтения, не будет иметь значения, поскольку больше ничего не пишется и не меняет значения под ногами. Или есть какая-то другая историческая причина? Я склонен сказать, что возвращение volatile void* будет более безопасным по умолчанию, и те, кто хочет эту оптимизацию, могут затем вручную привести к void *.

POSIX mmap описание: http://opengroup.org/onlinepubs/007908775/xsh/mmap.html

Ответы [ 6 ]

7 голосов
/ 09 июля 2010

Реализация разделяемой памяти - это только одна небольшая часть использования mmap(). На самом деле наиболее распространенными видами использования являются создание частных сопоставлений, как анонимных, так и с файловой поддержкой. Это означает, что, даже если мы примем ваше утверждение о необходимости указывать volatile -качественный указатель для доступа к общей памяти, такой классификатор будет излишним в общем случае.

Помните, что вы всегда можете добавить финальные квалификаторы к типу указателя без приведения, но вы не можете удалить их. Итак, с текущей mmap() декларацией вы можете сделать следующее:

volatile char *foo = mmap();  /* I need volatile */

и это:

char *bar = mmap();  /* But _I_ do not */

По вашему предложению пользователи в общем случае должны будут выбросить летучих.

6 голосов
/ 09 июля 2010

Глубокое предположение, распространяющееся на многие программные системы, заключается в том, что большинство программистов являются последовательными программистами. Это только недавно начало меняться.

mmap имеет десятки применений, не связанных с общей памятью. В случае, если программист пишет многопоточную программу, он должен предпринять свои собственные шаги для обеспечения безопасности. Защита каждой переменной мьютексом не используется по умолчанию. Аналогично, mmap не предполагает , что другой поток сделает спорный доступ к тому же сегменту совместно используемой памяти, или даже что сопоставленный таким образом сегмент будет доступен другому потоку.

Я также не уверен, что пометка возврата mmap как volatile повлияет на это. Программист все равно должен был бы обеспечить безопасность доступа к отображаемой области, не так ли?

4 голосов
/ 09 июля 2010

Быстрая изменчивость будет охватывать только одно чтение (которое в зависимости от архитектуры может быть 32-разрядным или что-то еще, и, следовательно, может быть весьма ограничивающим. Часто вам нужно будет написать более 1 машинного слова, и вы все равно получите ввести какую-то блокировку.

Даже если бы он был энергозависимым, вы могли бы легко иметь 2 процесса, считывающих разные значения из одной и той же памяти, все, что требуется, - это 3. процесс записи в память в наносекунду между чтением из процесса 1. и чтением из процесса 2. (если вы не можете гарантировать, что два процесса читают одну и ту же память в течение почти одинаковых тактов.

Таким образом - mmap () довольно бесполезно пытаться справиться с этими вещами, и программисту лучше решать, как обращаться с доступом к памяти и помечать указатель как энергозависимый, где это необходимо - если память используется совместно - вам будет необходимо, чтобы все участвующие стороны сотрудничали и знали, как они могут обновлять память по отношению друг к другу - что-то выходит за рамки mmap, а что-то утомительное не решит.

3 голосов
/ 09 июля 2010

Я не думаю, что volatile делает то, что вы думаете.

По сути, он просто говорит компилятору не оптимизировать переменную путем сохранения ее значения в регистре.Это заставляет его извлекать значение каждый раз, когда вы ссылаетесь на него, что является хорошей идеей, если другой поток (или что-то еще) мог обновить его за это время.

Функция возвращает void *, но она не собираетсябыть обновленным, поэтому называть его изменчивым бессмысленно.Даже если вы присвоите значение локальной изменчивой пустоте *, ничего не получится.

0 голосов
/ 09 июля 2010

Тип volatile void * или void * volatile не имеет смысла: вы не можете разыменовать void *, поэтому нет смысла указывать для него квалификаторы типа.

И, так как вам все равно требуется приведение к char * или какому-либо другому типу данных, то, возможно, это правильное место для определения волатильности. Таким образом, API, как он определен, удаляет ответственность за маркировку памяти, изменяемой под вашими ногами / энергозависимой.

Тем не менее, из большой картины POV, я согласен с вами: у mmap должен быть тип возврата, указывающий, что компилятор не должен кэшировать этот диапазон.

0 голосов
/ 09 июля 2010

Вероятно, так сделано из соображений производительности, по умолчанию ничего лишнего. Если вы знаете, что в вашей конкретной архитектуре процесс записи / чтения не будет переупорядочен процессором, вам может вообще не потребоваться энергозависимость (возможно, в сочетании с другой синхронизацией). РЕДАКТИРОВАТЬ: это был только пример - может быть множество других случаев, когда вы знаете, что вам не нужно принудительно перечитывать каждый раз при обращении к памяти.

Если вам нужно убедиться, что все адреса читаются из памяти при каждом обращении к ним, const_cast (или преобразование в стиле C) изменяет значение на возвращаемое значение самостоятельно.

...