Буферизация


Буферизация по многим причинам также является актуальным вопросом как для блочных, так и для символьных устройств. Чтобы понять, в чем состоит одна из таких причин, рассмотрим процесс, которому необходимо прочитать данные, получаемые от ADSL-модема, который многие используют дома для связи с Интернетом.
По одной из возможных стратегий работы с поступающими символами нужно заставить пользовательский процесс осуществить системный вызов read и заблокироваться в ожидании одного символа. При этом прерывание возникает по случаю поступления каждого символа. Процедура обработки прерывания передает символ пользовательскому процессу и снимает с него блокировку. Поместив куда-нибудь символ, процесс переходит к чтению следующего символа и снова блокируется. Эта модель показана на рис. 5.12, а.


Проблема реализации такого способа заключается в том, что пользовательский процесс должен возобновляться для каждого поступающего символа. Из-за низкой эффективности многократных краткосрочных запусков процесса это далеко не самая лучшая модель.

Улучшенный вариант показан на рис. 5.12, б. Здесь пользовательский процесс предоставляет буфер объемом п символов и выполняет чтение такого же количества символов. Процедура обработки прерывания помещает поступающие символы в этот буфер до тех пор, пока он не заполнится. Затем она возобновляет работу пользовательского процесса. Эта схема работает намного эффективнее предыдущей, но у нее есть один недостаток. Что получится, если буфер выйдет за границу страницы при поступлении очередного символа? Буфер будет зафиксирован в памяти, но если множество процессов начнет фиксировать страницы в памяти, то запас доступных страниц сократится и производительность резко снизится.

Другой подход предусматривает создание буфера внутри ядра и возложение на обработчик прерывания обязанности помещать символы в этот буфер (рис. 5.12, в).

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

Но даже эта улучшенная схема не обходится без проблемы. Что произойдет с символами, которые поступят в тот момент, когда страница с пользовательским буфером будет извлекаться с диска? Поскольку буфер заполнен, его будет некуда поместить. Выходом из положения может стать второй буфер ядра. Как показано на рис. 5.12, г, после заполнения первого буфера, но перед его опустошением используется второй буфер. Когда второй буфер заполнится, его можно будет скопировать в буфер пользователя (если предположить, что пользователь просил об этом). Пока второй буфер будет копироваться в пространство пользователя, для новых символов может использоваться первый буфер. Таким образом, два буфера работают по очереди: пока один из них копируется в пространство пользователя, другой аккумулирует новые поступления. Эта схема называется двойной буферизацией.

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

Оба указателя ходят по кругу, переходя обратно к нижним адресам буфера, как только достигнут его верхних адресов.

Буферизация играет важную роль и при выводе данных. Рассмотрим, к примеру, как осуществляется вывод данных на модем без буферизации с использованием модели, показанной на рис. 5.12, б. Пользовательский процесс, чтобы вывести n символов, осуществляет системный вызов write. В этот момент у системы есть два варианта выбора. Она может заблокировать пользовательский процесс до тех пор, пока не будут записаны все символы, но при использовании телефонной линии это займет очень много времени. Система может также немедленно освободить пользовательский процесс и заняться операциями ввода-вывода, пока этот процесс будет заниматься какими-то другими вычислениями, но это приведет к еще более серьезной проблеме. Как пользовательский процесс узнает, что вывод данных был завершен и он может опять воспользоваться буфером? Система может выставить сигнал или программное прерывание, но такой стиль программирования слишком сложен и склонен к созданию состязательных условий. Намного более удачным решением будет копирование ядром данных в буфер ядра аналогично варианту, показанному на рис. 5.12, в (но в обратную сторону), и сразу после этого разблокирование вызывающего процесса. Теперь неважно, когда фактически завершится процесс ввода-вывода. Пользовательский процесс с момента разблокирования может использовать буфер повторно.

Буферизация является широко используемой технологией, но у нее имеются и недостатки. Если данные будут подвергаться буферизации слишком часто, упадет производительность. Рассмотрим, к примеру, сеть, показанную на рис. 5.13. Здесь пользовательский процесс осуществляет системный вызов для записи данных по сети. Ядро копирует пакет данных в буфер ядра, позволяя пользовательскому процессу немедленно возобновить работу (шаг 1). Теперь пользовательская программа может использовать буфер повторно.

Когда вызывается драйвер, он копирует пакет в контроллер для его последующего вывода (шаг 2). Причина, по которой он не осуществляет вывод в сеть непосредственно из памяти ядра, состоит в том, что как только будет запущена передача пакета, она должна продолжаться на постоянной скорости. Драйвер не может гарантировать, что он будет получать доступ к памяти на постоянной скорости, поскольку множество циклов обращения к шине могут отвлекать на себя каналы DMA и другие устройства ввода-вывода. Неудача при своевременном получении слова приведет к порче пакета. Эту проблему можно устранить за счет буферизации пакета внутри контроллера.

Рис. 5.13. Передача данных по сети может сопровождаться многочисленным копированием пакета


После того как пакет будет скопирован во внутренний буфер контроллера, он копируется в сеть (шаг 3). Биты поступают получателю вскоре после их отправки, поэтому сразу же после отправки последнего бита этот бит поступает получателю, у которого пакет попадает в буфер контроллера. Затем пакет копируется в буфер ядра получателя (шаг 4). И наконец он копируется в буфер процесса получателя (шаг 5). Обычно после этого получатель посылает подтверждение. Когда отправитель получает подтверждение, он имеет возможность послать следующий пакет. Но при этом следует понимать, что операции копирования существенно снижают скорость передачи данных, поскольку шаги должны осуществляться последовательно.

<< | >>
Источник: Э. ТАНЕНБАУМ Х. БОС. СОВРЕМЕННЫЕ ОПЕРАЦИОННЫЕ СИСТЕМ Ы 4-е ИЗДАНИЕ. 2015

Еще по теме Буферизация:

  1. Л.О. Доліненко, В.О. Доліненко, С.О. Сарновська. Цивільне право України, 2006
  2. ЦИВІЛЬНЕ ПРАВО УКРАЇНИ
  3. ПЕРЕДМОВА
  4. Частина І ПРОГРАМА КУРСУ «ЦИВІЛЬНЕ ПРАВО УКРАЇНИ»
  5. Розділ І. Загальні положення цивільного права
  6. Тема 1. Поняття цивільного права. Предмет та метод, система цивільного права. Функції та принципи цивільного права
  7. Тема 2. Цивільне законодавство України
  8. Тема 3. Поняття, елементи та види цивільних правовідносин
  9. Тема 4. Здійснення цивільних прав і виконання обов’язків
  10. Тема 5. Захист цивільних прав та інтересів
  11. Тема 6. Об’єкти цивільних прав