#c #linux #process #ipc
#c #linux #процесс #ipc
Вопрос:
read()
Системный вызов заставляет ядро копировать данные вместо передачи буфера по ссылке. В интервью меня спросили о причине этого. Лучшее, что я мог придумать, это:
- Чтобы избежать одновременной записи в один и тот же буфер между несколькими процессами.
- Если процесс пользовательского уровня попытается получить доступ к буферу, сопоставленному области виртуальной памяти ядра, это приведет к сбою в сегменте.
Как оказалось, интервьюер не был полностью удовлетворен ни одним из этих ответов. Я был бы очень признателен, если бы кто-нибудь мог уточнить вышесказанное.
Ответ №1:
Реализация с нулевым копированием означала бы, что процессу пользовательского уровня должен быть предоставлен доступ к буферам, используемым внутренне ядром / драйвером для чтения. Пользователю пришлось бы выполнить явный вызов ядра, чтобы освободить буфер после того, как они с ним закончили.
В зависимости от типа считываемого устройства буферы могут представлять собой нечто большее, чем просто область памяти. (Например, некоторым устройствам может потребоваться, чтобы буферы находились в определенной области памяти. Или они могли бы поддерживать запись только в фиксированную область памяти, которая будет предоставлена им при запуске.) В этом случае неспособность пользовательской программы «освободить» эти буферы (чтобы устройство могло записать в них больше данных) может привести к тому, что устройство и / или его драйвер перестанут функционировать должным образом, чего пользовательская программа никогда не должна быть способна сделать.
Комментарии:
1. Обратите внимание, что, например, недавно в ядрах реализована поддержка ‘splice’, что означает, что для драйверов fuse теперь существуют пути с нулевым копированием
Ответ №2:
Буфер указан вызывающим объектом, поэтому единственный способ получить данные там — скопировать их. И API определен так, как он есть, по историческим причинам.
Обратите внимание, что ваши два пункта выше не являются проблемой для альтернативы, mmap
, которая передает буфер по ссылке (и записывает в него, чем записывает в файл, поэтому вы не можете обрабатывать данные на месте, в то время как многие пользователи read
делают именно это).
Комментарии:
1. С
MAP_PRIVATE
запись в map не изменяет файл.
Ответ №3:
Возможно, я был готов оспорить утверждение интервьюера. Буфер в read()
вызове предоставляется пользовательским процессом и, следовательно, поступает из пользовательского адресного пространства. Также не гарантируется, что они будут выровнены каким-либо определенным образом по фреймам страницы. Это затрудняет выполнение того, что необходимо для выполнения ввода-вывода непосредственно в буфер ie. сопоставьте буфер с адресным пространством драйвера устройства или подключите его к DMA. Однако в ограниченных обстоятельствах это может быть возможно.
Кажется, я помню, что подсистема BSD, используемая Mac OS X для копирования данных между адресными пространствами, была оптимизирована в этом отношении, хотя я могу полностью ошибаться.