Предположим, что пользовательскому процессу необходимо выполнить считывание блоков данных длиной по 512 байт по одному с магнитной ленты. Данные будут считаны в область внутри адресного пространства пользовательского процесса с виртуальным адресом от 1000 до 1511. Наиболее простой путь решения этой задачи — выполнение команды ввода-вывода (что-то наподобие Read_Block [1000, tape]) и ожидание того момента, когда данные станут доступными. Ожидание может быть либо активным, т.е. будет происходить непрерывное тестирование состояния устройства, либо, что более практично, процесс будет приостановлен до прерывания.
При таком подходе имеются две проблемы. Первая представляет собой приостановку программы для ожидания выполнения относительно медленного ввода-вывода. Вторая проблема состоит в том, что такой подход к вводу-выводу мешает свопингу. Виртуальные адреса с 1000 по 1511 должны находиться в основной памяти при считывании блока (в противном случае часть данных будет утеряна). При использовании страничной организации памяти по крайней мере одна страница (содержащая целевой адрес) должна быть заблокирована в основной памяти. Поэтому, несмотря на то что часть задания может быть выгружена на диск, полный свопинг процесса окажется невозможным, даже если это необходимо для операционной системы. Следует также учесть возможность взаимоблокировки. При генерации процессом команды ввода-вывода он приостанавливается и выгружается на диск до начала выполнения операции ввода-вывода. Далее процесс ожидает, когда будет выполнена запрошенная им операция ввода-вывода, которая, в свою очередь, ожидает, когда процесс будет возвращен в основную память, поскольку место в основной памяти для считывания данных попросту отсутствует. Для того чтобы избежать взаимоблокировки, пользовательская память, вовлеченная в операцию ввода-вывода, должна быть заблокирована в основной памяти сразу же после выдачи запроса на ввод-вывод, даже если операция ввода-вывода ставится в очередь и может быть выполнена только через некоторое время.
То же рассуждение применимо и к операции вывода. Если блок пересылается из адресного пространства пользовательского процесса в модуль ввода-вывода, то на время этой передачи процесс блокируется и не может быть выгружен на диск.
Чтобы уменьшить накладные расходы и увеличить эффективность, иногда удобно выполнить чтение данных заранее, до реального запроса (а запись данных — немного позже реального запроса). Эта методика известна как буферизация. В данном разделе мы рассмотрим некоторые схемы буферизации, поддерживаемые операционными системами для повышения производительности.
При рассмотрении различных методов буферизации важно учитывать, что существуют устройства ввода-вывода двух типов: блочно-ориентированные и поточно-ориентированного. Блочно-ориентированные устройства сохраняют информацию блоками, обычно фиксированного размера, и выполняют передачу данных поблочно. Как правило, при этом можно ссылаться на данные с использованием номера блока. Диски и магнитные ленты относятся к блочно-ориентированным устройствам ввода-вывода. Поточно-ориентированные устройства выполняют передачу данных в виде неструктурированных потоков байтов. К этой группе устройств относятся терминалы, принтеры, коммуникационные порты, манипулятор "мышь" и другие указывающие устройства, а также большинство устройств, не являющихся внешними запоминающими устройствами.