Операционные системы
ы, указатель - это данные, являющиеся атрибутом операционной
системы. Казалось бы, не логично, и сейчас мы рассмотрим, в чем эта
нелогичность проявляется. Для этого кратко рассмотрим концептуальные
вопросы, связанные с формированием процесса. Операционная система UNIX
имеет функцию fork(). Это системный вызов. При обращении к этому системному
вызову в системе происходит некоторое действие, которое для большинства из
вас может показаться бессмысленным, - происходит копирование процесса, в
котором встретилась эта функция, т.е. создается процесс-двойник. Для чего
это нужно, я скажу несколько позже.
Формирование процесса-двойника обладает следующими свойствами. Первое
свойство: процесс-сын, который будет сформирован после обращения к функции
fork(), имеет все те файлы, которые были открыты в процессе-отце. Второе -
система позволяет некоторыми своими средствами, идентифицировать, где
процесс-отец, а где процесс-сын, хотя в общем случае они абсолютно
одинаковы.
Предположим, есть процесс №1, и с ним ассоциирована таблица открытых
файлов №1. В этом процессе открыт файл с именем Name, и этому файлу
поставлен в соответствие файловый дескриптор I. Это означает, что в
соответствующей строке ТОФ будет запись, имеющая ссылку на ТФ. В ТФ
определены какие-то атрибуты, связанные с открытием файла, а также имеется
указатель чтения/записи, т.е. тот указатель, по которому мы работаем,
обмениваясь информацией с файлом. Записи в ТФ имеют ссылку на ТИДОФ, в
которой находится копия ИД, соответствующего файлу с именем Name.
Предположим, что в этом процессе еще раз открыт файл с именем Name.
Система поставила ему в соответствие файловый дескриптор J. Т.е. этому
открытию соответствует J-тая строка ТОФ первого процесса. В этой записи
будет ссылка на запись ТФ, которая поставлена в соответствие второму
открытию файла Name. И пока индексы наследственности для обоих случаев
будут равны единице. В этой записи будут свои, связанные с этим открытием,
указатели чтения/записи. Указатели файловых дескрипторов I и J независимы
друг от друга, т.е. при чтении/записи через файловый дескриптор I,
указатель файлового дескриптора J не изменится. Эта запись будет ссылаться
на тот же самый индексный дескриптор из ТИДОФ, и значение счетчика будет
равно двум.
Предположим, процесс №1 выполнил обращение к функции fork(),
образовалась копия процесса, причем, обе копии начинают работать на выходе
из fork(), и со вторым процессом будет ассоциирована ТОФ №2. Так же будет
открыт файл Name по ИД I и по ИД J. Но в этом случае, когда процесс получил
открытые файлы в наследство от родителя, то ссылки из соответствующих строк
ТОФ будут происходить не на новые записи ТФ, а на те же самые, к которым
ссылались соответствующие ФД у родителя. У этих процессов указатели чтения
записи будут одинаковы, т.е. если передвинуть указатель в одном процессе,
то он автоматически передвинется и для другого процесса. Этот случай, как
раз тот, когда нет взаимно однозначного соответствия между строками ТФ и
строками ТОФ. При порождении этих ссылок счетчик увеличивается на два. И,
соответственно, из ИД, за счет адресации блоков, осуществляется доступ к
блокам файлов. Такая информационная организация обмена означает, что обмен
с содержимым каждого файла осуществляется централизованно, т.е. в конечном
итоге, все заказы на обмен идут через одну единственную запись, сколько бы
файлов, связанных с этим ИД, не было открыто в системе. Здесь нет никаких
коллизий, когда во времени начинается путаница в выполненных, или
невыполненных обменах, связанных с одним дескриптором.
При любом формировании нового процесса, система априори устанавливает
нулевой, первый и второй файловые дескрипторы из ТОФ, связывая их с
предопределенными файлами. Нулевой ФД связан с системным файлом ввода, с
ним обычно ассоциировано внешнее устройство клавиатура. Первый ФД - это
стандартный файл вывода, обычно с ним ассоциирован экран монитора. Второй
ФД - это стандартный файл вывода диагностических сообщений, с ним также
обычно ассоциирован экран монитора.
Рассмотрим для примера типовые действия при обращении к тем или иным
системным вызовам.
Обращение к функции fork(). Как известно, при обращении к этой функции
система создает копию исходного процесса. При этом система дублирует ТОФ
одного процесса в ТОФ процесса-наследника, а также увеличивает на единицу
индекс наследственности в строках ТФ, ассоциированных с открытыми файлами
исходного процесс, а также увеличивает счетчик открытых файлов, связанных с
данным ИД, в ТИДОФ.
Обращение к функции open(). При обращении к этой функции происходит
следующее:
1. По полному имени определяется каталог, в котором размещен
файл.
2. Определяется номер ИД. По номеру ИД осуществляется поиск в
таблице ТИДОФ.
3. Если запись с заданным номером обнаружена, фиксируем номер
соответствующей строки ТИДОФ и переходим к шагу 5.
4. В случае если строка не обнаружена, происходит формирование
новой строки, соответствующей новому ИД и фиксируется ее
номер.
5. Корректируем счетчик ссылок (стрелок) на запись ТИДОФ. Номер
записи в ТИДОФ записывается в запись ТФ, а также в ТОФ
устанавливается ссылка на соответствующую запись ТФ. После
этого в программу возвращается номер сроки ТОФ, в которой
находится ссылка на запись в ТФ.
При операциях ввода/вывода действия системы очевидны.
Взаимодействие с устройствами. Мы уже говорили, что все устройства,
которые обслуживаются операционной системой UNIX, могут быть
классифицированы на два типа - байт-ориентированные устройства и блок-
ориентированные устройства. Следует отметить, что одно и то же устройство в
системе может рассматриваться и как байт-ориентированное, и как блок-
ориентированное (пример - оперативная память). Соответственно, есть
драйверы блок-ориентированные и байт-ориентированные. На прошлой лекции мы
рассматривали специальные файлы, ассоциированные с внешними устройствами, и
говорили о том, что есть таблица драйверов блок-ориентированных устройств
и таблица драйверов байт-ориентированных устройств. Соответственно, на эти
таблицы имеются ссылки в ИД специальных файлов.
Основной особенностью организации работы с блок-ориентированными
устройствами является возможность буферизации обмена. Суть заключается в
следующем. В оперативной памяти системы организован пул буферов, где
каждый буфер имеет размер в один блок. Каждый из этих блоков может быть
ассоциирован с драйвером одного из физических блок-ориентированных
устройств.
Рассмотрим, как выполняется последовательность действий при исполнении
заказа на чтение блока. Будем считать, что поступил заказ на чтение N-ого
блока из устройства с номером M.
1. Среди буферов буферного пула осуществляется поиск заданного
блока, т.е. если обнаружен буфер, содержащий N-ый блок М-ого
устройства, то фиксируем номер этого буфера. В этом случае,
обращение к реальному физическому устройству не происходит, а
операция чтения информации является представлением информации
из найденного буфера. Переходим на шаг 4.
2. Если поиск заданного буфера неудачен, то в буферном пуле
осуществляется поиск буфера для чтения и размещения данного
блока. Если есть свободный буфер (реально, эта ситуация
возможна только при старте системы), то фиксируем его номер и
переходим к шагу 3. Если свободного буфера не нашли, то мы
выбираем буфер, к которому не было обращений самое долгое
время. В случае если в буфере имеется установленный признак
произведенной записи информации в буфер, то происходит
реальная запись размещенного в буфере блока на физической
устройство. Затем фиксируем его номер и также переходим к
пункту 3.
3. Осуществляется чтение N-ого блока устройства М в найденный
буфер.
4. Происходит обнуление счетчика времени в данном буфере и
увеличение на единицу счетчиков в других буферах.
5. Передаем в качестве результата чтения содержимое данного
буфера.
Вы видите, что здесь есть оптимизация, связанная с минимизацией
реальных обращений к физическому устройству. Это достаточно полезно при
работе системы. Запись блоков осуществляется по аналогичной схеме. Таким
образом организована буферизация при низкоуровневом вводе/выводе.
Преимущества очевидны. Недостатком является то, что система в этом случае
является критичной к несанкционированным выключениям питания, т.е.
ситуация, когда буфера системы не выгружены, а происходит нештатное
прекращение выполнения программ операционной системы, что может привести к
потере информации.
Второй недостаток заключается в том, что за счет буферизации разорваны
во времени факт обращения к системе за обменом и реальный обмен. Этот
недостаток проявляется в случае, если при реальном физическом обмене
происходит сбой. Т.е. необходимо, предположим, записать блок, он
записывается в буфер, и получен ответ от системы, что обмен закончился
успешно, но когда система реально запишет этот блок на ВЗУ, неизвестно. При
| | скачать работу |
Операционные системы |