Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Системное программное обеспечение. Учебник

.pdf
Скачиваний:
0
Добавлен:
08.09.2026
Размер:
2 Мб
Скачать
☆
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].
При распределении ресурсов по приоритетному принципу может случиться так, что данный процесс будет бесконечно дол­го ждать выделения ему ресурса из-за прихода процессов с более высокими приоритетами. Для эффективного управления процес­сами ожидание не должно быть бесконечным. Поэтому с целью предотвращения бесконечного откладывания при ожидании ре­сурса приоритет процесса увеличивается по мере ожидания. Это называется старением процесса. В конце концов, ожидающий процесс получит более высокое значение приоритета, чем у всех приходящих процессов, и будет обслужен. Существует и фор­мальный аппарат для описания этих ситуаций – математическая теория очередей.
Операционная система выполняет функции администра- тора ресурсов. Она отвечает за распределение обширных на­боров ресурсов различных типов. Оперативно распределяемые ресурсы – это центральный процессор и основная память. Са­мым динамичным ресурсом является центральный процессор. Он должен работать в режиме быстрого переключения (муль­типлексирования), обслуживая большое число конкуриру­ющих процессов. Данные и программы – это также ресурсы, которые требуют соответствующей организации управления и распределения. Поэтому при распределении ресурсов могут возникать не только разрешимые конфликтные ситуации,
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]