обрабатывать данные из общего файла. Во всех этих случаях
возникает проблема синхронизации процессов, которая может
решаться приостановкой и активизацией процессов, организацией
очередей, блокированием и освобождением ресурсов.
Общие данные
%
-клиент
R
Принт-
сервер
раз явленный ресурс
R
S
Эффект "гонок"
Рисунок 9 - Пример необходимости синхронизации
Рассмотрим, например (рисунок 9), программу печати файлов
(принт-сервер). Эта программа печатает по очереди все файлы, имена
которых последовательно в порядке поступления записывают в
специальный общедоступный файл «заказов» другие программы.
Переменная NEXT, доступная всем процессам-клиентам, содержит
номер первой свободной позиции файла «заказов». Процессы-клиенты
читают эту переменную, записывают в соответствующую позицию
файла «заказов» имя необходимого файла и наращивают значение
31
NEXT на единицу. Предположим, что в некоторый момент процесс R
решил распечатать свой файл, для этого он прочитал значение
переменной
NEXT
(значение
которой
для
определенности
предположим равным 4). Процесс запомнил это значение, но
поместить имя файла не успел, так как его выполнение было прервано
(например, в следствие исчерпания кванта). Очередной процесс S,
желающий распечатать файл, прочитал то же самое значение
переменной NEXT, поместил в четвертую позицию имя своего файла
и нарастил значение переменной на единицу. Когда в очередной раз
управление будет передано процессу R, то он, продолжая свое
выполнение, в полном соответствии со значением текущей свободной
позиции, полученным во время предыдущей итерации, запишет имя
файла также в позицию 4, поверх имени файла процесса S.
Таким образом, процесс S никогда не увидит свой файл
распечатанным. В общем случае исход такой ситуации (были
потеряны файлы нескольких процессов или, напротив, не был потерян
ни один файл) определяется взаимными скоростями процессов и
моментами их прерывания. Ситуации, когда два или более процессов
обрабатывают разделяемые данные, и конечный результат зависит от
соотношения скоростей процессов, называются гонками.
Критическая
секция.
Важным
понятием
синхронизации
процессов является понятие «критическая секция» программы.
Критическая секция - это часть программы, в которой осуществляется
доступ к разделяемым данным. Чтобы исключить эффект гонок по
отношению к некоторому ресурсу, необходимо обеспечить, чтобы в
каждый момент в критической секции, связанной с этим ресурсом,
находился максимум один процесс. Этот прием называют взаимным
исключением.
Простейший
способ
обеспечить
взаимное
исключение -
позволить процессу, находящемуся в критической секции, запрещать
все прерывания. Однако этот способ непригоден, так как опасно
доверять управление системой пользовательскому процессу.
Другим
способом
является
использование
блокирующих
переменных. С каждым разделяемым ресурсом связывается двоичная
переменная, которая принимает значение 1, если ресурс свободен, и
значение 0, если ресурс занят. На рисунке 10 показан фрагмент
алгоритма процесса, использующего для реализации взаимного
исключения доступа к разделяемому ресурсу D блокирующую
переменную F(D). Перед входом в критическую секцию процесс
проверяет, свободен ли ресурс D. Если он занят, то проверка
циклически повторяется, если свободен, то значение переменной F(D)
32
устанавливается в 0, и процесс входит в критическую секцию. После
того, как процесс выполнит все действия с разделяемым ресурсом D,
значение переменной F(D) снова устанавливается равным 1.
Запрос виполнон
Рисунок 10 - Реализация критических секций с использованием
блокирующих переменных
Если все процессы написаны с использованием вышеописанных
соглашений, то взаимное исключение гарантируется.
Реализация критических секций с использованием блокирующих
переменных имеет существенный недостаток: в течение времени,
когда один процесс находится в критической секции, другой процесс,
которому требуется тот же ресурс, будет выполнять рутинные
действия по опросу блокирующей переменной, бесполезно тратя
процессорное время. Для устранения таких ситуаций может быть
использован так называемый аппарат событий. С помощью этого
средства могут решаться не только проблемы взаимного исключения,
но и более общие задачи синхронизации процессов. В разных
операционных системах аппарат событий реализуется по своему, но в
любом случае используются системные функции аналогичного
назначения, которые условно назовем WAIT(x) и POST(x), где х -
33
идентификатор некоторого события. На рисунке 11 показан фрагмент
алгоритма процесса, использующего эти функции. Если ресурс занят,
то процесс не выполняет циклический опрос, а вызывает системную
функцию WAIT(D), здесь D обозначает событие, заключающееся в
освобождении ресурса D. Функция WAIT(D) переводит активный
процесс в состояние «ожидание» и делает отметку в его дескрипторе о
том, что процесс ожидает события D. Процесс, который в это время
использует ресурс D, после выхода из критической секции выполняет
системную функцию POST(D), в результате чего операционная
система просматривает очередь ожидающих процессов и переводит
процесс, ожидающий события D, в состояние «готовность». В этом
случае
блокирующая
переменная
является
частным
случаем
семафоров (в общем случае семафор может принимать не только
значения 0 или 1).
Снятие блокировки со всех
процессов, ожидающих ресурс D
Рисунок 11 - Реализация критической секции с использованием
системных функций WAIT(D) и POST(D)
Достоинство синхронизации на основе семафорных операций -
отсутствие активного ожидания представления ресурса.
34