системный вызов read() делает копию данных вместо передачи ссылки


Системный вызов

read() заставляет ядро копировать данные вместо передачи буфера по ссылке. Меня спросили о причине этого в интервью. Лучшее, что я смог придумать, было:

  1. чтобы избежать одновременной записи в один и тот же буфер между несколькими процессами.
  2. Если процесс на уровне пользователя попытается получить доступ к буферу, сопоставленному с областью виртуальной памяти ядра, это приведет к segfault.

Как оказалось, интервьюер не был полностью удовлетворен любой из этих ответов. Я был бы очень признателен, если бы кто-нибудь мог подробнее остановиться на этом.

3 2

3 ответа:

Буфер задается вызывающим объектом, поэтому единственный способ получить данные-скопировать их. И API определяется так, как он есть, по историческим причинам.

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

Реализация нулевого копирования будет означать, что процесс пользовательского уровня должен получить доступ к буферам, используемым внутренним ядром / драйвером для чтения. Пользователь должен был бы сделать явный вызов ядру, чтобы освободить буфер после того, как они закончили с ним.

В зависимости от типа считываемого устройства буферы могут быть не только областью памяти. (Например, некоторые устройства могут требовать, чтобы буферы находились в определенной области памяти. Или они могли только поддержка записи в фиксированную область памяти предоставляется им при запуске.) В этом случае неспособность пользовательской программы "освободить" эти буферы (чтобы устройство могло записать в них больше данных) может привести к тому, что устройство и/или его драйвер перестанут функционировать должным образом, что пользовательская программа никогда не сможет сделать.

Возможно, я был готов оспорить утверждение интервьюера. Буфер в вызове read() предоставляется пользовательским процессом и, следовательно, поступает из адресного пространства пользователя. Он также не гарантирует, что будет выровнен каким-либо определенным образом по отношению к фреймам страниц. Это делает его сложно сделать то, что необходимо для выполнения ввода-вывода непосредственно в буфер ie. сопоставьте буфер с адресным пространством драйвера устройства или подключите его к DMA. Однако в ограниченных обстоятельствах это может быть возможный.

Я, кажется, помню, что подсистема BSD, используемая Mac OS X для копирования данных между адресными пространствами, имела оптимизацию в этом отношении, хотя я могу полностью ошибаться.