
- •Раздел 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.10. Примитивы ядра для обмена сообщениями
Напомню, что мы классифицировали примитивы ядра на три группы:
примитивы управления процессами;
примитивы синхронизации процессов;
примитивы обмена данными.
Синхронизация и обмен данными вместе называются обобщенно взаимодействием.
Если опять построить некоторую многоуровневую классификацию, то примитивы второго и третьего класса следует поместить в следующую иерархическую схему:
Вопрос (
Обмен данными
─────────────
Синхронизация
)Вопрос
Т.е. обмен данными - это логически более высокий уровень взаимодействия процессов, чем синхронизация.
Обмен данными не может быть реализован без синхронизации.
При этом средства синхронизации «встраиваются» в средства обмена данными таким образом, что они оказываются скрытыми от пользователя.
Пользователю предоставляется пара примитивов типа: SEND, RECEIVE или READ, WRITE.
Обмен данными может рассматриваться в двух аспектах.
обмен происходит между процессами, выполняющимися на одной физической машине;
обмен происходит между процессами, выполняющимися на различных физических машинах.
В данном параграфе мы рассмотрим первый вариант обмена данными, рассматривая средства обмена как примитивы ядра. Мы увидим, кстати, что эти примитивы подпадают под определение понятия МОНИТОР, рассмотренное выше. Обмену данными в целом, с учетом возможности выполнения взаимодействующих процессов на различных машинах, посвящен специальный раздел, рассматривающий восьмой уровень базовой классификации операционной среды - уровень коммуникаций.
Как и ранее, мы рассмотрим модели обмена данными, а затем приведем примеры средств обмена данными в реальных операционных средах. Базовым средством обмена данными между процессами является средство, называемое буфером.
3.10.1. Буфер как средство коммуникации между процессами
При организации связи между процессами с помощью любого средства требуется составить спецификацию к этому средству.
Вопрос (
Спецификация буфера как средства связи выглядит следующим образом:
сообщения в буфере имеют фиксированный размер;
размер буфера ограничен, буфер - кольцевой;
посылка сообщения в полный буфер недопустима;
чтение сообщения из пустого буфера также недопустима.
)Вопрос
Перечислив условия функционирования буфера, можно построить его описание, рассматривая буфер в виде монитора.
Вопрос (
Type
PBuffer = ^TBuffer;
TBuffer = Object
N : [0..N]; {текущее количество сообщений в буфере}
in : [0..N-1]; {индекс ячейки, в которую производится текущая запись}
out : [0..N-1]; {индекс ячейки, из которой производится текущее чтение}
Buf : Array[0..N-1] Of TMessage;
RList : PList; {очередь процессов, ждущих чтения}
WList : PList; {очередь процессов, ждущих записи}
Constructor Init;
Destructor Done;
Procedure Write(M : TMessage);
Procedure Read(Var M : TMessage);
End {TBuffer};
)Вопрос
Схема использования буфера выглядит следующим образом.
Var
B : PBuffer;
Begin
B := New(PBuffer, Init);
...
Dispose(B, Done);
End.
Процесс 1: Процесс 2:
Procedure Производитель; Procedure Потребитель;
Var Var
Message : TMessage; Message : TMessage;
Begin Begin
While True Do Begin While True Do Begin
... ...
Сформировать(Message); B^.Read(Message);
B^.Write(Message); Обработать(Message);
... ...
End {While}; End {While};
End {Производитель}; End {Потребитель};
Целью использования буфера при обмене данными между процессами является согласование скоростей записи и чтения информации различными процессами. Если скорости записи и чтения одинаковы, то рисунок состояния буфера будет выглядеть примерно так:
Если скорость чтения превышает скорость записи, то схема состояния буфера будет выглядеть следующим образом.
Вопрос (
)Вопрос
Т.е. буфер будет большее время пустым, чем занятым, а процесс, читающий из буфера, будет ждать записи. Если скорость записи превышает скорость чтения, то схема состояния буфера будет выглядеть следующим образом.
Вопрос (
)Вопрос
Т.е. буфер будет большее время полным, чем свободным, а процесс, записывающий в буфер, будет ждать чтения.
Распишем теперь методы монитора БУФЕР.
Constructor TBuffer.Init;
Begin
N := 0;
in := 0;
out := 0;
RList := New(PList, Init);
WList := New(PList, Init);
End {TBuffer.Init};
Destructor TBuffer.Done;
Begin
Dispose(RList, Done);
Dispose(WList, Done);
End {TBuffer.Done};
Вопрос (
Procedure TBuffer.Write(M : TMessage);
Begin
Запрет прерываний;
If n = N Then Begin {буфер полон}
WList^.Insert(Текущий процесс); {ждем записи}
ПЕРЕНАЗНАЧИТЬ ПРОЦЕССОР;
End {If};
Inc(n);
Buf[in] := M;
in := (in + 1) MOD N;
If RList не пустая Then Begin {активизация ждущего чтения}
Очередь_готовых.Insert(Текущий процесс);
RList^.Remove(Первый процесс);
Передать управление(Текущий процесс, Первый процесс);
End {If};
Разрешение прерываний;
End {TBuffer.Write};
)Вопрос
Вопрос (
Procedure TBuffer.Read(Var M : TMessage);
Begin
Запрещение прерываний;
If n = 0 Then Begin
RList^.Insert(Текущий процесс); {ждем чтения}
ПЕРЕНАЗНАЧИТЬ ПРОЦЕССОР;
End {If};
Dec(n);
M := Buf[out];
out := (out + 1) MOD N;
If WList не пустая Then Begin {активизация ждущего записи}
Очередь_готовых.Insert(Текущий процесс);
WList^.Remove(Первый процесс);
Передать управление(Текущий процесс, Первый процесс);
End {If};
Разрешение прерываний;
End {TBuffer.Read};
)Вопрос
Выводы
Внешне работа с буфером напоминает работу с файлом: Создать; Записать; Прочитать; Разрушить; Работа любых средств обмена данными похожа на эти действия.
Две очереди процессов используются в качестве средств синхронизации записи и чтения. Вместо прямого использования очередей могут использоваться семафоры. В этом случае нужна пара семафоров, которые имеют смысл «НЕ_ПУСТ» и «НЕ_ПОЛОН». Когда процесс пишет сообщение в буфер, а он оказывается полным, процесс выполняет операцию НЕ_ПОЛОН.Р. Если буфер не полон и операция записи прошла успешно, то процесс выполняет операцию НЕ_ПУСТ.V, активизируя читающий процесс, ждущий записи. Когда процесс читает сообщение из буфера, а он оказывается пустым, процесс выполняет операцию НЕ_ПУСТ.Р. Если буфер не пуст и операция чтения прошла успешно, то процесс выполняет операцию НЕ_ПОЛОН_V, активизируя пишущий процесс, ждущий чтения.
Вопрос (
Недостатками буфера являются: 1) фиксированный размер буфера; 2) реальная перезапись данных в буфер и из буфера.
)Вопрос
Следующий метод обмена данными устраняет недостатки буфера.