
- •Раздел 3. Параллельное выполнение программ
- •3.1. Концепция процесса
- •3.2. Средства описания параллелизма
- •3.2.1. Графические средства
- •3.2.3. Описание процессов средствами uml
- •3.2.4. Языковые средства описания параллелизма
- •3.3. Организация ядра ос
- •3.3.1. Ядро как средство организации виртуальной машины
- •3.3.2. Состояния процесса и структура ядра
- •3.3.3. Дескрипторы процессов
- •3.3.4. Очереди процессов в ядре
- •3.4. Общая характеристика примитивов ядра
- •3.5. Примитивы создания и уничтожения процессов
- •3.6. Примитивы синхронизации процессов
- •3.6.1. Простейшие примитивы, не учтенные в классификации
- •3.6.2. Примитивы временной синхронизации
- •3.6.3. Примитивы событийной синхронизации процессов
- •3.7. Общий семафор как средство событийной синхронизации
- •3.8. Средства синхронизации в существующих операционных системах
- •3.9. Монитор как средство реализации взаимного исключения
- •3.10. Примитивы ядра для обмена сообщениями
- •3.10.1. Буфер как средство коммуникации между процессами
- •3.10.2. Почтовый ящик с очередью сообщений
- •3.10.3. Средства коммуникаций в существующих ос
- •3.11. Проблема тупиков при взаимодействии процессов
- •3.12. Планирование загрузки процессора в ядре
- •3.12.1. Классификация алгоритмов планирования
- •3.12.2. Тесты планируемости задач и классификация задач
- •3.12.3. Динамическое планирование
- •3.12.3.1. Планирование независимых задач
- •1. Алгоритм монотонной скорости.
- •2. Алгоритм “задача с минимальным предельным сроком завершения - первая”
- •3. Алгоритм минимальной неопределенности
- •3.12.3.2. Планирование зависимых задач
- •3.12.4. Статическое планирование
3.6.3. Примитивы событийной синхронизации процессов
Мы уже знаем, что существуют следующие понятия:
критический ресурс - разделяемый ресурс, с которым могут работать несколько параллельных процессов;
критический участок - участок программы процесса, в котором описаны действия с критическим ресурсом;
режим взаимного исключения - режим выполнения критического участка без передачи управления от одного процесса к другому.
Важно, что проблема доступа к критическому ресурсу связана не с числом процессоров, на которых выполняются процессы, а именно с общим ресурсом.
Пример: N - счет в центральном банке. С двух терминалов делается попытка его изменить.
Ожидаем результат: N = N + S1 + S2;
Можем получить: N = N + S1; или N = N + S2.
Общая идея решения этой проблемы состоит в том, что только один процесс должен работать в критическом участке, а все остальные, подойдя к своим критическим участкам, должны ЖДАТЬ, когда ресурс освободится. Т. е., если один процесс вошел в критический участок, то никакой другой процесс не может в него войти. Когда процесс, который работал в критическом участке, выйдет из него, может входить в свой критический участок другой процесс.
Проблема организации такой очередности вхождения процессов в критические участки является ключевой проблемой параллельного программирования.
Вход в критический участок и выход из него рассматриваются как события. Поэтому средства решения этой проблемы и называются средствами событийной синхронизации.
Существуют аппаратные и программные способы решения этой проблемы в зависимости от логического уровня, на котором рассматривается эта проблема.
Дадим их краткий обзор.
Вопрос (
запрет прерываний
маскирование прерываний только от таймера
использование флага занятости ресурса
)Вопрос
Первое средство, которое напрашивается само собой - запрет прерываний на входе критического участка и разрешение прерываний на выходе из него.
P1: P2:
cli cli
Критический участок; Критический участок;
sti sti
Этот способ имеет следующие недостатки:
Вопрос (
закрываются все прерывания; система становится «слепой» и «глухой» для всех внешних воздействий на время выполнения критического участка; поэтому этот способ может быть использован только для коротких критических участков, и он так и используется; но это - базовое средство, поэтому оно в том или ином виде присутствует во всех остальных средствах.
приостанавливается выполнение всех процессов, кроме, естественно, активного процесса, даже тех, которые и не собираются использовать критический ресурс.
)Вопрос
Второй способ. Запрет не всех прерываний, а маскирование прерываний только от таймера. Это более тонкий метод. Он устраняет первый из недостатков первого способа организации взаимного исключения, состоящий в том, что система перестает реагировать на любые внешние сигналы. Но второй недостаток, состоящий в том, что процессы, не имеющие отношения к данному критическому ресурсу, тоже приостанавливаются, так и не устранен.
Третий способ. Устанавливается флаг занятости ресурса.
Например:
Flag = 0 - ресурс свободен;
Flag = 1 - ресурс занят.
Процесс перед входом в критический участок проверяет значение флага. Если флаг равен нулю, то процесс устанавливает флаг в состояние 1 (занят) и входит в критический участок. Если флаг равен единице, то процесс снова переходит на проверку значения флага.
При выходе из критического участка процесс устанавливает флаг в состояние 0 (свободен).
Вариант без метки:
M: If Flag = 1 Then GoTo M; While Flag = 1 Do ;
Flag := 1;
Критический участок;
Flag := 0;
Оказывается, что этот способ не снимает проблемы. «Откомпилируем» предыдущий код:
M: cmp Flag,1
jz M
mov Flag, 1
Критический участок;
mov Flag, 0
Предположим, что Flag = 0 и передача управления происходит сразу же за инструкцией
cmp Flag,1
и второй процесс выполняет инструкцию cmp Flag,1. Для обоих процессов Flag окажется равным нулю и они оба войдут в критический участок.
Это происходит потому, что Flag сам является критическим ресурсом и доступ к нему надо организовывать в режиме взаимного исключения:
M1 : cli или M1 : sti
cmp Flag,1 cli
jnz M2 cmp Flag,1
sti jz M1
jmp M1 mov Flag,1
M2 : mov Flag,1 sti
sti Критический участок;
Критический участок; mov Flag,0
mov Flag,0
Третий вариант с инструкцией «обменять» - xchg:
mov ax,1
M: xchg ax,Flag
Cmp ax,1
jz M
Критический участок;
mov Flag,0
Если Flag = 0, то Flag установится в 1, а ax установится в 0, и процесс войдет в критический участок.
Если Flag = 1, то он останется в 1 и ax останется в 1, и процесс перейдет на метку М, т.е. будет ждать установки Flag в 0.
Чтение и установка флага производятся за одну инструкцию, а это - неделимое действие по определению.
Отметим, что здесь начинают фигурировать очень низкоуровневые, практически, аппаратные средства. К таким аппаратным средствам относится блокировка магистрали, которой можно обеспечивать неделимость некоторых инструкций. Блокировка магистрали при выполнении инструкции XCHG осуществляется по умолчанию.
Вводя в программе префикс LOCK, можно обеспечить блокировку магистрали при выполнении некоторых других инструкций: INC, DEC, ADD, SUB, AND, OR.
Загрузка TSS осуществляется при блокировке магистрали.
Выводы по третьему способу обеспечения взаимного исключения
Способ имеет достоинство, состоящее в том, что критический участок с флагом имеет маленькую и фиксированную длину.
Способ иллюстрирует важную идею обеспечения взаимного исключения, состоящую в том, что для доступа к одному – основному ресурсу необходимо захватить другой - дополнительный ресурс.
Способ не избавляет от «активного ожидания» – цикла опроса флага до его освобождения.
Способ, как и два предыдущих иллюстрирует общую структуру участка программы, работающего с критическим ресурсом – это наличие логических скобок - вход в критический участок и выход из критического участка:
Вход;
Критический участок;
Выход;
Стремление устранить последний недостаток привело к появлению других, более высокоуровневых средств, которые мы и будем считать примитивами ядра для событийной синхронизации процессов.
Семафоры как примитивы ядра и средство синхронизации
Общая идея всех последующих способов состоит в том, что если процессу приходится ждать освобождения ресурса, то пусть он ждет этого в специальной очереди.
Вопрос(
Так появились двоичный и общий семафор Дейкстры.
)Вопрос
Вопрос (
Двоичный семафор содержит флаг, который свидетельствует о занятости или незанятости ресурса, и очередь, в которой находится процесс, если ресурс занят. При инициализации флаг находится в состоянии «свободен», а очередь пуста.
)Вопрос
Над семафором выполняются две операции, соответствующие входу в критический участок и выходу из него.
Вопрос (
Вход:
Запрет_прерываний;
If Flag = Занят Then Begin
Встать в очередь;
ПЕРЕНАЗНАЧИТЬ_ПРОЦЕССОР;
End {If};
Flag := Занят;
Разрешение_прерываний;
)Вопрос
Вопрос (
Выход:
Запрет_прерываний;
Flag := Свободен;
If Очередь не пуста Then Begin
Перевести первый процесс из этой очереди
в очередь готовых процессов;
ПЕРЕНАЗНАЧИТЬ_ПРОЦЕССОР;
End {If};
Разрешение_прерываний;
)Вопрос
Вопрос (
Особенности семафора:
вставая в очередь семафора до освобождения ресурса, процесс разгружает процессор;
на каждый ресурс нужен свой семафор, а значит, своя очередь, поэтому в ядре и много очередей;
семафор - это тоже разделяемый ресурс, а значит, действия с ним должны выполняться в режиме взаимного исключения; более того, если рассматривать семафор как примитив ядра, вместо операции Запрет_прерываний необходимо ставить операции ПРОЛОГ, КОНТРОЛЬ.
)Вопрос
Вопрос (
Использование семафора обеспечивает возможность безостановочной работы процессов, не требующих ресурсов.
)Вопрос