
- •Глава 11
- •Глава 12. Управление файлами
- •Глава 11 Управление вводом-выводом и дисковое планирование
- •11.1. Устройства ввода-вывода
- •11.2. Организация функций
- •11.3. Вопросы проектирования операционных систем
- •11.4 Буферизация операций ввода-вывода
- •11.5. Дисковое планирование
- •Выбор в соответствии с источником запроса
- •Выбор в соответствии с содержимым запроса
- •11.6. Raid
- •Буфер кэша
- •Очередь символов
- •Небуферизированный ввод-вывод
- •11.9. Ввод-вывод в windows 2000
- •Асинхронный и синхронный ввод-вывод
- •11.10. Резюме, ключевые термины и контрольные вопросы
- •Ключевые термины
- •Рекумендуемая литература
- •11.12. Задачи
- •Приложение. Дисковые устройства Магнитный диск
- •Оптическая память
11.4 Буферизация операций ввода-вывода
Предположим, что пользовательскому процессу необходимо выполнить считывание блоков данных длиной по 512 байт по одному с магнитной ленты. Данные будут считаны в область внутри адресного пространства пользовательского процесса с виртуальным адресом от 1000 до 1511. Наиболее простой путь решения этой задачи — выполнение команды ввода-вывода (что-то наподобие Read_Block [1000, tape]) и ожидание того момента, когда данные станут доступными. Ожидание может быть либо активным, т.е. будет происходить непрерывное тестирование состояния устройства, либо, что более практично, процесс будет приостановлен до прерывания.
При таком подходе имеются две проблемы. Первая представляет собой приостановку программы для ожидания выполнения относительно медленного ввода-вывода. Вторая проблема состоит в том, что такой подход к вводу-выводу мешает свопингу. Виртуальные адреса с 1000 по 1511 должны находиться в основной памяти при считывании блока (в противном случае часть данных будет утеряна). При использовании страничной организации памяти по крайней мере одна страница (содержащая целевой адрес) должна быть заблокирована в основной памяти. Поэтому, несмотря на то что часть задания может быть выгружена на диск, полный свопинг процесса окажется невозможным, даже если это необходимо для операционной системы. Следует также учесть возможность взаимоблокировки. При генерации процессом команды ввода-вывода он приостанавливается и выгружается на диск до начала выполнения операции ввода-вывода. Далее процесс ожидает, когда будет выполнена запрошенная им операция ввода-вывода, которая, в свою очередь, ожидает, когда процесс будет возвращен в основную память, поскольку место в основной памяти для считывания данных попросту отсутствует. Для того чтобы избежать взаимоблокировки, пользовательская память, вовлеченная в операцию ввода-вывода, должна быть заблокирована в основной памяти сразу же после выдачи запроса на ввод-вывод, даже если операция ввода-вывода ставится в очередь и может быть выполнена только через некоторое время.
То же рассуждение применимо и к операции вывода. Если блок пересылается из адресного пространства пользовательского процесса в модуль ввода-вывода, то на время этой передачи процесс блокируется и не может быть выгружен на диск.
Чтобы уменьшить накладные расходы и увеличить эффективность, иногда удобно выполнить чтение данных заранее, до реального запроса (а запись данных — немного позже реального запроса). Эта методика известна как буферизация. В данном разделе мы рассмотрим некоторые схемы буферизации, поддерживаемые операционными системами для повышения производительности.
При рассмотрении различных методов буферизации важно учитывать, что существуют устройства ввода-вывода двух типов: блочно-ориентированные и поточно-ориентированного. Блочно-ориентированные устройства сохраняют информацию блоками, обычно фиксированного размера, и выполняют передачу данных поблочно. Как правило, при этом можно ссылаться на данные с использованием номера блока. Диски и магнитные ленты относятся к блочно-ориентированным устройствам ввода-вывода. Поточно-ориентированные устройства выполняют передачу данных в виде неструктурированных потоков байтов. К этой группе устройств относятся терминалы, принтеры, коммуникационные порты, манипулятор "мышь" и другие указывающие устройства, а также большинство устройств, не являющихся внешними запоминающими устройствами.
Одинарный буфер
Простейшим типом поддержки со стороны операционной системы является одинарный буфер (рис. 11.6,6). В тот момент, когда пользовательский процесс выполняет запрос ввода-вывода, операционная система назначает ему буфер в системной части основной памяти.
Схема одинарного буфера для блочно-ориентированных устройств может быть описана следующим образом. Сначала осуществляется передача входных данных в системный буфер. Когда она завершается, процесс перемещает блок в пользовательское пространство и немедленно производит запрос следующего блока. Такая процедура называется опережающим считыванием, или упреждающим вводом; она выполняется в предположении, что этот блок со временем будет затребован. Для многих типов задач этот метод в большинстве случаев неплохо работает, поскольку доступ к данным обычно осуществляется последовательно (только при окончании последовательности обработки считывание блока будет излишним).
Такой подход, по сравнению с отсутствием буферизации, обеспечивает повышение быстродействия. Пользовательский процесс может обрабатывать один блок данных в то время, когда происходит считывание следующего блока. Операционная система при этом может осуществить выгрузку процесса, поскольку выполняется операция считывания данных в системную память, а не в память пользовательского процесса. Однако такая технология усложняет функционирование операционной системы, которая должна следить за назначением системных буферов пользовательским процессам. Влияет буферизация и на схему подкачки: когда операция ввода-вывода работает с тем же диском, который используется и для свопинга, теряется смысл в организации очереди операций записи. Выгрузка процесса и освобождение основной памяти не начнется до тех пор, пока не завершится запрошенная операция ввода-вывода — а тогда выгрузка процесса больше не будет иметь смысла.
Рис. 11.6, Схемы буферизации ввода-вывода (ввод)
Похожие рассуждения применимы и к блочно-ориентированному выводу. Если данные передаются на устройство, то сначала они копируются из пользовательского пространства в системный буфер, из которого они в конечном счете будут записаны на устройство. В этой ситуации выводящий данные процесс может продолжать работу сразу же после передачи данных в системный буфер.
В книге [KNUT97] приводится грубое, но очень показательное сравнение процессов при использовании одинарной буферизации и при ее отсутствии. Предположим, что Т — это время, необходимое для ввода одного блока, а С — для вычислений, выполняющихся между запросами на ввод данных. Без буферизации общее время выполнения, приходящееся на один блок, будет равно Т + С. При использовании одинарной буферизации время выполнения равно mах[С, Т] + М, где М — время, необходимое для перемещения данных из системного буфера в пользовательскую память. В большинстве случаев это время значительно меньше времени работы без буферизации.
Схема одинарного буфера может быть применена и при поточно-ориентированном вводе-выводе — построчно или побайтово. Построчная буферизация применима, например, в неинтеллектуальных терминалах, где пользователь вводит данные построчно, завершая строки символом возврата каретки, сигнализируя об окончании строки; вывод на терминал происходит таким же образом — построчно. Другим примером может служить строчный принтер. Побайтовые операции применяются при использовании терминалов с формами, а также многих других периферийных устройств, когда каждое нажатие клавиши является значимым.
В случае построчного ввода-вывода буфер может быть использован для хранения одной строки. Пользовательский процесс приостанавливается на время ввода, ожидая поступления целой строки. При операции вывода пользовательский процесс может разместить строку в буфере и продолжить работу. Необходимость приостановления этого процесса возникает только в том случае, если требуется вывод второй строки, в то время как первая еще не покинула буфер. При побайтовом вводе-выводе, взаимодействие операционной системы и пользовательского процесса следует модели производителя/потребителя, рассмотренной в главе 5, "Параллельные вычисления: взаимоисключения и многозадачность".
Двойной буфер
Улучшить схему одинарной буферизации можно путем использования двух системных буферов (рис. 11.6,в). Теперь процесс выполняет передачу данных в один буфер (или считывание из него), в то время как операционная система освобождает (или заполняет) другой. Эта технология известна как двойная буферизация или сменный буфер.
Время выполнения при блочно-ориентированной передаче данных можно грубо оценить как mах[С, Т]. Таким образом, если С < Т , то блочно-ориентированное устройство может работать с максимальной скоростью. Если же С > Т , то двойная буферизация избавляет процесс от необходимости ожидания завершения ввода-вывода. В любом случае достигается преимущество перед одинарной буферизацией. Это улучшение буферизации осуществляется за счет увеличения ее сложности.
При поточно-ориентированном вводе мы снова обращаемся к двум альтернативным режимам работы. Необходимость приостановления процесса при построчном выводе возникает только в том случае, если при выводе очередной строки оба буфера не пусты. При побайтовых операциях двойной буфер не имеет никакого преимущества перед одинарным буфером двойной длины. В обоих случаях используется модель производителя/потребителя.
Циклический буфер
Схема двойного буфера призвана выровнять поток данных между устройством ввода-вывода и процессом. Если нас интересует производительность некоторого процесса, то в первую очередь требуется, чтобы операции ввода-вывода не тормозили его работу. Двойная буферизация может оказаться недостаточной, если процесс часто выполняет ввод или вывод. Зачастую в таком случае решить проблему помогает наращивание количества буферов.
При использовании множества буферов, состоящего более чем из двух элементов, схема именуется циклической буферизацией (рис. 11.6,г). В ней каждый индивидуальный буфер представляет собой модуль циклического буфера. Такая буферизация описывается моделью производителя/потребителя с ограниченным буфером, которая рассматривалась в главе 5, "Параллельные вычисления: взаимоисключения и многозадачность".
Использование буферизации
Буферизация представляет собой метод сглаживания всплесков количества запросов ввода-вывода. Однако никакое количество буферов не позволит устройству ввода-вывода работать наравне с процессом в течение неограниченного времени в ситуации, когда средняя скорость запросов процесса превышает возможности их обработки устройством ввода-вывода. Даже при наличии большого количества буферов в конечном счете все они будут заполнены, и процесс будет вынужден приостановиться в ожидании обработки порции данных устройством ввода-вывода. Однако в многозадачной среде при наличии разнообразных процессов с запросами ввода-вывода и такого же разнообразия устройств буферизация оказывается инструментом, способным увеличить как производительность операционной системы в целом, так и производительность отдельных процессов.