Может ли `read ()` следовать непосредственно за `write ()` и `write ()` за `read ()`? - PullRequest
0 голосов
/ 30 августа 2018

В стандартной библиотеке C за выводом не может следовать ввод, и наоборот.

Для Linux API, могут ли сразу следовать read() write() и write() read()? Если да, то почему такая разница между Linux API и IO API библиотеки C?

Спасибо.

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Напомним другой ответ, когда вы используете stdio, вы работаете с буфером, который не является реальным файлом. Этот буфер должен быть скопирован из фактического файла (через вызов OS read), если вы читаете, и он должен быть скопирован в фактический файл (через вызов OS write), если вы пишете. Если вы слишком поспешно переключаетесь, скажем, с записи на чтение, код stdio не осознает, что он должен очистить записанный буфер и перезагрузить буфер для чтения.

С другой стороны, при использовании системных вызовов read и write все иначе. Во-первых, вы можете читать и записывать устройство (например, последовательный порт или сетевой поток TCP), и в этом случае, очевидно, нет проблем с возвратом назад и между чтением и записью.

Но даже если вы используете системные вызовы read и write для чтения и записи файла, вы обращаетесь к файлу - или, по крайней мере, к представлению ОС о файле - напрямую. Ни одна из проблем, упомянутых для буферов stdio, не применяется.

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

Как объяснено в другом ответе, процедуры stdio могли бы быть написаны для поддержки чередующегося ввода-вывода, но не в интересах простоты и эффективности.

Почему так? Еще одна часть загадки заключается в том, что в первые дни C и Unix системные вызовы были чрезвычайно дорогими. Системный вызов может занять в 10 или 100 раз больше, чем обычный вызов функции. Таким образом, было действительно важно избегать ненужных системных вызовов, и библиотека stdio была большой частью этого. Для заполнения буфера требуется один вызов read, а затем вы можете совершать множество небольших вызовов для извлечения отдельных (или небольшого числа) символов из буфера без дополнительных затрат. Точно так же во время записи вы можете сделать много маленьких вызовов, чтобы написать небольшое количество символов, а затем есть только один дорогой write вызов для очистки буфера. Если бы поддержка stdio поддерживала чередование операций чтения и записи - что не рассматривалось как важный вариант использования - потребовалось бы больше системных вызовов, или больше тестов, или большего количества кода (или всех трех), и в целом это было бы дороже, чем это стоило.

(Сегодня системные вызовы гораздо менее неэффективны, поэтому, если бы сегодня C и Unix разрабатывались с нуля, различие между системными вызовами read и write и входными и выходными вызовами stdio могло бы сработать по-другому.)

0 голосов
/ 30 августа 2018

Вашему другому вопросу (связанному) не хватает контекста. Когда он говорит: «Когда файл открыт для чтения и записи (знак плюс в типе), применяются два ограничения.», Это относится к файлам, которые открываются и обрабатываются с использованием потоков FILE * (например, fopen, fscanf, fprintf и т. Д.), А не дескрипторы файлов (например, open, read, write и т. Д.).

Только FILE * потоки обычно имеют связанные буферы stdio; дескрипторы файлов не имеют никаких связанных буферов (могут быть другие буферы на более низких уровнях, такие как ядро, контроллеры дисков и т. д., но об этом вам обычно не нужно беспокоиться). Так что read(2) и write(2) ничего не буферизируют (нет буферов stdio). Поэтому у них нет таких ограничений порядка ввода / вывода.

...