
- •Раздел 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.6.1. Простейшие примитивы, не учтенные в классификации
Это примитивы Приостановить_Процесс и Возобновить_Процесс. Для описания этих примитивов вспомним 2-й вывод предыдущего параграфа об очередях.
Для реализации этих примитивов создается специальная очередь приостановленных процессов. Тогда структура примитивов будет иметь следующий вид:
Procedure Приостановить_Процесс(P : Process);
Begin
ПРОЛОГ;
КОНТРОЛЬ;
<
Вывести процесс Р из очереди, в которой он находится;
Ввести процесс Р в очередь приостановленных процессов;
>
ПЕРЕНАЗНАЧИТЬ_ПРОЦЕССОР;
End {Приостановить_Процесс};
Procedure Возобновить_Процесс(P : Process);
Begin
ПРОЛОГ;
КОНТРОЛЬ;
<
Вывести процесс Р из очереди приостановленных процессов;
Ввести процесс Р в очередь готовых процессов;
>
ПЕРЕНАЗНАЧИТЬ_ПРОЦЕССОР;
End {Возобновить_Процесс};
Замечания
Вид этих примитивов реализует общую идею приостановки/возобновления, которая может быть реализована по-разному.
Эта самая простейшая форма примитивов для случая недлительных задержек. При длительных приостановках необходимо освободить ресурсы, которыми владеет процесс.
В некоторых ОС при приостановке процесса Р необходимо приостанавливать и всех его потомков. Другой вариант состоит в том, что только своих потомков и может приостанавливать процесс. Все эти ограничения учитываются обработкой полей дескриптора процесса.
Распространенным способом использования этих примитивов является приостановка процесса, ошибочно вошедшего в бесконечный цикл. Прерванный таким образом процесс передается в специальную очередь неправильно работающих процессов, которая обрабатывается специальным обработчиком ошибок. Внешне реакция похожа на исключение.
Приведенные примитивы можно рассматривать как первую попытку синхронизации действий нескольких процессов.
3.6.2. Примитивы временной синхронизации
Вопрос (
При временной синхронизации ВРЕМЯ выступает в качестве меры длительности явлений.
)Вопрос
Вопрос (
Забегая вперед, скажем, что в других случаях не важна абсолютная длительность явлений, а важны только соотношения РАНЬШЕ/ПОЗЖЕ.
)Вопрос
Проблемы временной синхронизации решаются с помощью примитива
Задержать_Процесс(Р : Process; T : Integer)
Здесь Т рассматривается как целое число, т. к. время в машине измеряется количеством «тиков» - интервалов времени между прерываниями от таймера.
Вопрос (
В однозадачных системах аналогом данного примитива является вызов процедуры Delay(T), которая может быть использована и в многозадачной среде. Моделью этой задержки является цикл следующего вида:
… …
Delay(T); For k := 0 To N Do ;
… …
Вопрос состоит только в выборе подходящего значения N.
В любом случае этот вариант реализует «активное ожидание», т. е. задерживаемый таким образом процесс все равно выполняется, занимая процессор, хотя и ничего не делает полезного.
В многозадачной системе такому процессу, выполняющему «пустую» работу так же, как и другим процессам, диспетчер выделяет кванты времени на выполнение.
Поэтому для системы в целом гораздо выгоднее снять такой процесс с выполнения (а именно из очереди готовых процессов) на время задержки и не предоставлять ему процессорное время, тем самым, улучшив условия выполнения других процессов.
Т. е. опять задержка процесса - это снятие его из очереди готовых процессов и перевод его в другую, специально предназначенную для задержек на время, очередь.
)Вопрос
Совершенно понятно, как поставить процесс в очередь. Встает вопрос, когда его из этой очереди извлечь и перевести в очередь готовых процессов.
Если процесс ставится в очередь в текущий момент времени Тт, и время, на которое он ставится в очередь, равно Т, то активизировать его надо в текущий момент времени Та = Тн + Т.
На схеме Т = 7.
В ядре информацией о текущем времени владеет диспетчер, т.к. это обработчик прерываний от таймера - счетчика времени.
Диспетчер подсчитывает время в виде «тиков», поэтому извлекать процессы из очереди задержанных на время процессов лучше всего диспетчеру. Делать это надо тогда, когда текущее время совпадет с временем активизации процесса.
Время активизации процесса вычисляется по формуле Та := Тт+Т в момент постановки в очередь задержанных на время процессов и записывается в специальное поле в дескрипторе процесса.
Не остается ничего иного, как на каждом прерывании от таймера при вызове диспетчера в самом вызове диспетчера просматривать всю очередь задержанных процессов и сверять текущее время с временами активизации процессов, стоящих в этой очереди. При совпадении текущего времени с временем активизации, процесс извлекается из очереди задержанных и переводится в очередь готовых процессов.
Существует аналогия с уничтожением процессов. Примитив Уничтожить_Процесс переводит процесс в очередь уничтожаемых процессов, а диспетчер на каждом такте очищает эту очередь.
Здесь: примитив Задержать_Процесс переводит процесс в очередь задержанных процессов, а диспетчер на каждом такте эту очередь анализирует и активизирует процессы, для которых совпало текущее время с временем активизации.
В соответствие с изложенным структура примитивов задержки и активизации будет иметь следующий вид:
Вопрос (
Procedure Задержать_Процесс(P : Process; T : Integer);
Begin
ПРОЛОГ;
КОНТРОЛЬ;
<
Вывести процесс Р из очереди, в которой он находится;
Ввести процесс Р в очередь задержанных на время процессов;
Установить поле дескриптора процесса Р в соответствие с
формулой Та := Тт + Т;
>
ПЕРЕНАЗНАЧИТЬ_ПРОЦЕССОР;
End {Задержать_Процесс};
)Вопрос
Вопрос (
Procedure АКТИВИЗАЦИЯ_ЗАДЕРЖАННЫХ_НА_ВРЕМЯ_ПРОЦЕССОВ;
Begin
Для всех процессов из очереди задержанных делать следующее:
Если Время активизации процесса равно текущему времени, то
1) Вывести процесс из очереди задержанных на время процессов;
2) Ввести процесс в очередь готовых процессов;
End {АКТИВИЗАЦИЯ_ЗАДЕРЖАННЫХ_НА_ВРЕМЯ_ПРОЦЕССОВ};
)Вопрос
Процедуру АКТИВИЗАЦИЯ_ЗАДЕРЖАННЫХ_НА_ВРЕМЯ_ПРОЦЕССОВ необходимо поместить в Диспетчер:
Procedure Dispatcher; Interrupt;
Begin
АКТИВИЗАЦИЯ_ЗАДЕРЖАННЫХ_НА_ВРЕМЯ_ПРОЦЕССОВ;
ОЧИСТИТЬ_ОЧЕРЕДЬ_УНИЧТОЖАЕМЫХ_ПРОЦЕССОВ;
ПЕРЕНАЗНАЧИТЬ_ПРОЦЕССОР;
End;
Если очередь задержанных на время процессов отсортирована по возрастанию времени активизации, скорость анализа очереди можно увеличить, что важно, т.к. очередь анализируется в обработчике прерываний.