Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Системное программное обеспечение. Учебник
.pdf
111
Глава 4. Параллелизм в операционных системах
должна решить, какое подмножество параллельных ветвей будет выполняться одновременно.
Способ «редукция дерева» реализуется следующим образом. Применяя ассоциативные, коммутативные и дистрибутивные свойства арифметики, компиляторы могут обнаруживать
неявный параллелизм в алгебраических выражениях и генерировать объектный код для мультипроцессорных систем с указанием операций, которые можно выполнять одновременно.
Компиляторы должны действовать в соответствии со старшинством операций (приоритетом). Эти правила в основном сводятся к следующей последовательности операций (в порядке убывания приоритета):
• операции во вложенных скобках, причем сначала те, ко-
торые имеют более высокий уровень вложенности;
• операции в скобках;
• операции возведения в степень;
• операции умножения и деления;
• операции сложения и вычитания.
Если операции имеют одинаковый приоритет, то они выполняются слева направо, например [1]:
а) ((p + q) + r) + s б) (p + q) + (r + s)
1 2 3 1 2 1
Используя ассоциативность сложения, можно преобразовать
выражение ((p + q) + r) + s в выражение (p + q) + (r + s), которое
приспособлено для параллельных вычислений. На рис. 4.1 приведены соответствующие диаграммы, на которых цифры 1, 2, 3
показывают порядок, в котором должны выполняться операции.
На рис. 4.1, а изображена структура дерева, показывающего, каким образом обычный компилятор может генерировать код программы для выполнения приведенных операций.
Как видно на рис. 4.1, структуре первого выражения соответствует трехуровневое дерево, а структуре второго – лишь двухуровневое. Поэтому последнее выражение (рис. 4.1, б) можно
выполнять гораздо быстрее в мультипроцессорной системе.
При организации взаимодействия процессов решается ряд
задач, решение которых является достаточно сложным. Основные из этих задач и связанные с ними проблемы рассматриваются ниже.

СИСТЕМНОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ
+
+
+
P q r
s
1
2
3
+
+
+
P
q
1
1
r
s
2
а
б
112
Рис. 4.1. Уменьшение высоты дерева за счет ассоциативности
Подчеркнем, что при рассмотрении вопросов синхрониза-
ции вычислительных процессов из разделяемых ими ресурсов
исключаются центральный процессор и программы, реализующие эти процессы. С логической точки зрения каждому процессу соответствуют свои процессор и программа, хотя в реальных
системах обычно несколько процессов разделяют один процессор и одну или несколько программ. Многие ресурсы вычислительной системы могут совместно использоваться несколькими
процессами, но в каждый момент времени к разделяемому ресурсу может иметь доступ только один процесс. Ресурсы, которые не допускают одновременного использования несколькими
процессами, называются критическими. В том случае, когда нескольким вычислительным процессам необходимо пользоваться
критическим ресурсом в режиме разделения, этим процессам
следует синхронизировать свои действия таким образом, чтобы
ресурс всегда находился в распоряжении не более чем одного из
процессов. Если один процесс пользуется в данный момент критическим ресурсом, то все остальные процессы, которым нужен
этот ресурс, должны получить отказ и ждать, пока он не освободится. Если в операционной системе не предусмотрена защита
от одновременного доступа процессов к критическим ресурсам,
в ней могут возникать ошибки, которые трудно обнаружить и исправить. Основной причиной возникновения этих ошибок является то, что процессы в мультипрограммных операционных си-

113
Глава 4. Параллелизм в операционных системах
стемах развиваются с различными скоростями, а относительные
скорости развития каждого из взаимодействующих процессов
неизвестны и не подвластны ни одному из них. Более того, на их
скорости могут влиять решения планировщиков, касающиеся
других процессов, с которыми ни одна из этих программ не взаимодействует. Кроме того, содержание одного процесса и скорость
его исполнения обычно неизвестны другому процессу. Поэтому
влияние, которое оказывают друг на друга взаимодействующие
процессы, не всегда предсказуемо и воспроизводимо.
Задача взаимоисключения решается, если каждому процессу предоставить монопольное, исключительное право доступа
к разделяемым (общим) переменным. Это означает, что каждый
процесс, обращающийся к разделяемым данным, исключает
для всех других процессов возможность одновременного с ним
обращения к этим данным. Такая проблема называется взаимо-
исключением [2, 5]. Важным понятием, связанным с этой проблемой, являются критические участки.
Взаимоисключение необходимо только в том случае, когда
процессы обращаются к разделяемым, общим данным. Если же
они выполняют операции, которые не приводят к конфликтным ситуациям, они должны иметь возможность работать параллельно. Когда процесс производит обращение к разделяемым данным, то говорят, что он находится в своем критическом
участке (области). Для решения задачи взаимоисключения
необходимо, чтобы, когда один процесс входит в критическую
область, другие процессы, которые обращаются к общим с ним
данным, не входили в свои критические участки. Когда процесс
выходит из своего критического участка, то одному из остальных процессов, ожидающих входа в их критические участки,
должно быть разрешено продолжить работу (если есть такой
процесс в состоянии ожидания) [1].
Процессы должны как можно быстрее проходить критические участки, не должны в этот момент блокироваться, поэтому эти участки кодируются особенно тщательно.
Параллельная программа обычно содержит конструкции
«вход взаимоисключения»/«выход взаимоисключения» для
каждого процесса, а внутри этого участка программы обеспечивается доступ к разделяемым переменным. Таким образом, ука-

СИСТЕМНОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ
114
занные конструкции обрамляют критический участок. Подобные конструкции, или операторы, называются примитивами
взаимоисключения. Если два процесса выполняют «вход взаимоисключения» одновременно, то только одному из них будет
разрешено продолжить работу, а другому придется ждать («победитель» выбирается случайным образом).
В случае одновременных попыток нескольких процессов
обратиться к одному и тому же элементу данных возможные
конфликты разрешаются аппаратно при помощи схемы защитной блокировки памяти [1, 3].
Изящную программную реализацию механизма взаимоисключения впервые предложил голландский математик Деккер [3, 5].
Алгоритм Деккера основан на использовании трех переменных [5]: переключение1, переключение2, очередь. Первые
два – типа boolean, а очередь – integer. При условии, когда оба
процесса хотят выполнить свои критические интервалы, значение переменной «очередь» указывает, чье сейчас право делать попытку входа в свой критический интервал.
Если переключение2 = true и переключение1= false, то выполняется критический интервал процесса2 независимо от значения переменной «очередь». Аналогично для случая переключения2 = false и переключение1 = true. Для N процессов процедура
усложняется настолько, что практически не используется [2].
Далее алгоритм Деккера был усовершенствован. Например, Дейкстра усовершенствовал вариант алгоритма Деккера
для двух процессов, он первым предложил программное решение проблемы взаимоисключения для N процессов (программная реализация соответствующих примитивов) [1, 2, 5].
Существует аппаратное решение проблемы взаимоисключения. Для этого нужно наличие одной аппаратной команды,
которая осуществляет чтение переменной, запись ее значения
в область сохранения и установку нужного конкретного значения этой переменной. Подобная команда, называемая testand-
set (проверить и установить), после запуска выполняет все эти
действия до конца без прерывания. Неделимая команда: tes-
tandset (a, b) читает значение логической переменной b, копи-
рует его в а, а затем устанавливает для b значение «истина».

115
Глава 4. Параллелизм в операционных системах
Глобальная переменная «активный» – логического типа,
имеет значение «истина», когда любой из процессов находится в своем критическом участке, и значение «ложь» в противном случае [2, 5]. «Процесс один» принимает решение о входе
в свой критический участок в зависимости от значения своей
локальной логической переменной – «первому входить нельзя». Он устанавливает для этой переменной значение «истина»,
а затем многократно выполняет команду проверки и установки для глобальной логической переменной «активный». Если
«Процесс два» находится вне критического участка, переменная «активный» будет иметь значение «ложь».
Понятие семафорных механизмов было введено Дейкстрой
[2, 5]. Все описанные выше понятия, относящиеся к взаимоисключению, Дейкстра суммировал в своей концепции семафоров. Семафор – это защищенная переменная, значение которой
можно опрашивать и менять только при помощи специальных
операций P и V и операции инициализации, которую называют
«инициализация семафора». Двоичные семафоры могут принимать только значения 0 и 1. Считающие семафоры (семафоры со счетчиками) могут принимать неотрицательные целые
значения. Операция P над семафором S записывается как P(S)
и выполняется следующим образом:
если S>0
то S:= S-1
иначе (ожидать на S).
Операция V над семафором S записывается: V(S), а выполняется следующим образом:
если (один или более процессов ожидают на S)
то (разрешить одному из этих процессов продолжить работу)
иначе S:= S+1.
Очередь процессов, ожидающих на S, обслуживается в соответствии с дисциплиной «первый пришедший обслуживается первым» (FIFO).
Таким образом, под семафором понималась переменная
специального типа, которая доступна параллельным процессам для проведения над ней только двух операций: «закрытия»
и «открытия», названных соответственно операциями P и V. Эти

СИСТЕМНОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ
116
операции являются примитивами относительно семафора, который указывается в качестве параметра операций (семафорные
примитивы Дейкстры). Здесь семафор исполняет роль вспомогательного критического ресурса, так как операции P и V неделимы при своем выполнении и взаимно исключают друг друга.
Семафорный механизм работает по схеме, в которой сначала исследуется состояние критического ресурса, идентифицируемое значением семафора, а затем осуществляется доступ
к критическому ресурсу или отказ от него на некоторое время.
Основным достоинством использования семафорных операций является отсутствие состояния активного ожидания,
что может существенно повысить эффективность работы мультипрограммной вычислительной системы.
Подобно операции проверки и установки testandset, операции P и V являются неделимыми. Участки взаимоисключения по семафору S в процессах обрамляются операциями P(S)
и V(S). Если одновременно несколько процессов попытаются
выполнить операцию P(S), это будет разрешено только одному
из них, а остальным придется ждать.
Семафоры и операции над ними могут быть реализованы как программно, так и аппаратно. Как правило, они реализуются в ядре операционной системы, где осуществляется
управление сменой состояний процессов [2, 3, 5].
Синхронизация процессов при помощи семафоров осуществляется следующим образом. Когда процесс выдает запрос ввода-вывода, он блокирует себя в ожидании завершения соответствующей операции ввода-вывода. Заблокированный процесс
должен быть активизирован каким-либо другим процессом. Такое взаимодействие является примером функций, относящихся
к протоколу блокирования/возобновления.
Таким образом, семафоры можно использовать для реализации механизма синхронизации процессов путем блокирования/возобновления. В этом случае один процесс блокирует
себя (выполняя операцию P(S) с начальным значением S = 0),
чтобы подождать наступления некоторого события; другой
процесс обнаруживает, что ожидаемое событие произошло,
и возобновляет заблокированный процесс (при помощи операции V(S)).

117
Глава 4. Параллелизм в операционных системах
В паре «производитель – потребитель» один процесс, источник или производитель, генерирует информацию. Эту информацию использует другой процесс – получатель или потребитель.
Таким образом осуществляется взаимодействие между процессами.
Для реализации взаимоисключения разработчики придумали механизмы и более высокого уровня, самым важным из которых является монитор, первый вариант, которого предложил
Дейкстра.
Монитор – это механизм организации параллелизма, который содержит как данные, так и процедуры, необходимые для
реализации динамического распределения конкретного общего ресурса или группы общих ресурсов. Информация спрятана внутри монитора, процессы, обращающиеся к монитору, не
знают, какие данные находятся внутри монитора, и не получают к ним доступа.
Взаимоисключение процессов жестко обеспечивается на границе монитора, в каждый конкретный момент времени войти
в монитор разрешается только одному процессу. Каждой причине, по которой процесс может быть переведен в состояние ожидания, соответствует своя переменная – условие. Когда определяется такая переменная, тем самым устанавливается очередь.
Процесс, выдающий команду ожидания wait, включается в эту
очередь; процесс, выдающий команду сигнализации signal, позволяет ожидающему процессу выйти из очереди и войти в монитор.
При обмене данными между процессами используются такие
понятия, как процесс-производитель и процесс-потребитель,
а также кольцевой буфер. Причем вычислительные процессы
при выполнении разделяют ресурсы системы. Также следует
подчеркнуть, что при рассмотрении вопросов синхронизации вычислительных процессов из разделяемых ими ресурсов исключаются центральный процессор и программы, реализующие эти
процессы, то есть с логической точки зрения каждому процессу
соответствуют свои процессор и программа, хотя в реальных системах обычно несколько процессов разделяют один процессор
и одну или несколько программ. Многие ресурсы вычислительной системы могут совместно использоваться несколькими про-

СИСТЕМНОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ
118
цессами, но в каждый момент времени к разделяемому ресурсу может иметь доступ только один процесс. Ресурсы, которые
не допускают одновременного использования несколькими процессами, называются критическими. Как отмечено ранее, в том
случае, когда нескольким вычислительным процессам необходимо пользоваться критическим ресурсом в режиме разделения,
то им следует синхронизировать свои действия таким образом,
чтобы ресурс всегда находился в распоряжении не более чем одного из процессов. Все остальные процессы, которым нужен этот
ресурс, должны получить отказ и ждать, пока он не освободится.
Как известно, если в операционной системе не предусмотрена защита от одновременного доступа процессов к критическим ресурсам, в ней могут возникать ошибки, которые трудно обнаружить
и исправить [4]. Кроме того, как отмечалось выше, на их скорости могут влиять решения планировщиков, касающиеся других
процессов, с которыми ни одна из этих программ не взаимодействует. Поскольку содержание одного процесса и скорость его исполнения обычно «неизвестны» другому процессу, то влияние,
которое оказывают друг на друга взаимодействующие процессы,
не всегда предсказуемо и воспроизводимо.
Кольцевой буфер – это структура данных, широко применяемая в операционной системе для буферизации обменов
между процессом-производителем и процессом-потребителем.
При этом выдаются следующие сигналы [2, 4, 5]:
1) процесс-производитель (когда буфер заполнен) вызывает
вход wait (буфер не заполнен), а когда помещает данные в буфер, выдает сигнал signal (буфер не пустой);
2) процесс-потребитель, обнаруживший, что буфер пуст, вызывает вход wait (буфер не пустой), а при извлечении данных
из буфера, выдает сигнал signal (буфер не заполнен).
Таким образом, если процессы взаимодействуют при помощи
общего буфера, то источник не должен выдавать информацию,
когда буфер заполнен, а получатель не должен пытаться принять
информацию, если буфер пустой. Создание подобного режима
взаимодействия является примером синхронизации процессов.
При этом следует помнить, что если одна процедура вызывает
другую и передает ей данные, то обе процедуры являются частями единого процесса, то есть не выполняются параллельно.

119
Процесс А
Процесс В
Ресурс 1
Ресурс 2
Глава 4. Параллелизм в операционных системах
4.7. Предотвращение тупиковых ситуаций
В мультипрограммной системе процесс находится в состоянии тупика (дедлока или клинча), если он ожидает некоторого
события, которое никогда не произойдет. Системная тупиковая ситуация, или «зависание» системы, – это ситуация, когда один или более процессов оказываются в состоянии тупика.
На графе распределения ресурсов могут быть представлены два
процесса и два ресурса в состоянии простой тупиковой ситуации (рис. 4.2).
Рис. 4.2. Простая тупиковая ситуация
Здесь каждый процесс ждет, чтобы другой процесс освободил нужный ему ресурс, причем каждый не освобождает свой
ресурс до тех пор, пока другой не освободит свой ресурс, и т.д.
В операционной системе тупики возникают в результате
конкуренции за обладание выделяемыми или закрепляемыми
ресурсами, то есть ресурсами, которые в каждый момент времени отводятся только одному пользователю и которые называют ресурсами последовательного использования.
Системы спулинга часто оказываются подвержены тупикам. Режим спулинга (ввода-вывода с буферизацией) применяется для повышения производительности системы путем изолирования программы от периферийного (низкоскоростного)
устройства (например, принтера и т.д.). Чтобы повысить скорость, данные записывают сначала на более высокоскоростное
устройство, где они временно хранятся до момента распечат-

СИСТЕМНОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ
120
ки. Если емкость буфера будет заполнена до того, как завершится задача (например, запись в файл спулинга), то может
возникнуть тупиковая ситуация. Выход – перезапуск, рестарт
системы с потерей всей работы до этого момента. Для восстановления работоспособности считается иногда более целесообразным уничтожить одно или несколько заданий, чтобы
у остальных заданий оказалось достаточно свободного места
в буфере для завершения их работы. Поэтому при генерации
операционной системы системный программист задает размер
буферных файлов для спулинга. Один из способов избежать
тупиков при спулинге – предусмотреть больше места для файлов спулинга, чем предварительно требуется. Или же предусматривается динамическое распределение буферной памяти,
то есть с выделением при необходимости дополнительной памяти [1, 2, 4].
При распределении ресурсов по приоритетному принципу
может случиться так, что данный процесс будет бесконечно долго ждать выделения ему ресурса из-за прихода процессов с более
высокими приоритетами. Для эффективного управления процессами ожидание не должно быть бесконечным. Поэтому с целью
предотвращения бесконечного откладывания при ожидании ресурса приоритет процесса увеличивается по мере ожидания. Это
называется старением процесса. В конце концов, ожидающий
процесс получит более высокое значение приоритета, чем у всех
приходящих процессов, и будет обслужен. Существует и формальный аппарат для описания этих ситуаций – математическая
теория очередей.
Операционная система выполняет функции администра-
тора ресурсов. Она отвечает за распределение обширных наборов ресурсов различных типов. Оперативно распределяемые
ресурсы – это центральный процессор и основная память. Самым динамичным ресурсом является центральный процессор.
Он должен работать в режиме быстрого переключения (мультиплексирования), обслуживая большое число конкурирующих процессов. Данные и программы – это также ресурсы,
которые требуют соответствующей организации управления
и распределения. Поэтому при распределении ресурсов могут
возникать не только разрешимые конфликтные ситуации,
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
