Почему не делает POSIX mmap, возвращают энергозависимую пустоту*?

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

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

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

10
задан Joseph Garvin 8 July 2010 в 20:28
поделиться

6 ответов

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

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

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

6
ответ дан 3 December 2019 в 19:31
поделиться

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

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

0
ответ дан 3 December 2019 в 19:31
поделиться

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

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

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

3
ответ дан 3 December 2019 в 19:31
поделиться

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

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

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

и так:

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

С вашим предложением пользователям в общем случае придется отбрасывать volatile.

7
ответ дан 3 December 2019 в 19:31
поделиться

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

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

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

0
ответ дан 3 December 2019 в 19:31
поделиться

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

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

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

4
ответ дан 3 December 2019 в 19:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: