
- •Раздел 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.2. Почтовый ящик с очередью сообщений
Вопрос (
Недостаток буфера, заключающийся в фиксированном его размере, устраняется путем использования динамического объекта - очереди сообщений.
Недостаток буфера, заключающийся в реальной перезаписи данных, устраняется путем помещения в очередь указателей на сообщения, а не самих сообщений.
)Вопрос
В качестве средств синхронизации записи и чтения по-прежнему будем использовать очереди процессов.
Опишем объект, удовлетворяющий приведенной выше спецификации, и назовем его почтовым ящиком.
Type
TPostBox = ^TPostBox;
TPostBox = Object
TList : PList; {очередь процессов, пославших сообщение}
RList : PList; {очередь процессов, ждущих сообщения}
MList : PList; {очередь указателей на сообщения}
Constructor Init;
Destructor Done;
Procedure PutMsg(M : Pointer);
Procedure GetMsg(Var M : Pointer);
End {TPostBox};
Замечания
Схема использования почтового ящика в прикладной программе аналогична схеме использования буфера.
Из двух очередей - процессов, пославших сообщение, и процессов, ждущих сообщение, в произвольный момент времени существует только одна.
Процессы, естественно, знают тип сообщений как тип данных.
Сonstructor TPostBox.Init;
Begin
RList := New(PList, Init);
TList := New(PList, Init);
MList := New(PList, Init);
End {TPOstBox.Init};
Destructor TPostBox.Done;
Begin
Dispose(RList, Done);
Dispose(TList, Done);
Dispose(MList, Done);
End {TPostBox.Done};
Procedure TPostBox.PutMsg(M : Pointer);
Begin
Запрет прерываний;
MList^.Insert(M);
TList^.Insert(Текущий процесс);
If RList не пуста Then
RList^.Remove(Первый процесс)
Else
Очередь_готовых.Remove(Первый процесс);
Передать управление(Текущий процесс, Первый процесс);
Разрешение прерываний;
End {TPostBox.PutMsg};
Procedure TPostBox.GetMsg(Var M : Pointer);
Begin
Запрещение прерываний;
If MList пуста Then Begin
RList^.Insert(Текущий процесс); {ждем записи}
ПЕРЕНАЗНАЧИТЬ ПРОЦЕССОР;
End {If};
MList^.Remove(Первое сообщение);
M := Первое сообщение;
Tlist^.Remove(Первый процесс);
Очередь_готовых.Insert(Текущий процесс);
Передать управление(Текущий процесс, Первый процесс);
Разрешение прерываний;
End {TPostBox.GetMsg};
Приведенные примитивы работают следующим образом.
Предположим, что первым к примитиву почтового ящика подойдет процесс, записывающий сообщение. Он помещает его в очередь сообщений, а сам встает в очередь процессов, пославших сообщение. Процесс, подошедший вторым к примитиву чтения сообщения, считывает его из очереди сообщений и активизирует процесс, пославший его.
Теперь предположим, что первым к примитиву почтового ящика подойдет процесс, читающий сообщение. Он проверяет наличие сообщений в очереди сообщений и при их отсутствии блокируется в очереди ждущих сообщение. Процесс, подошедший вторым к примитиву записи сообщения, помещает сообщение в очередь, сам встает в очередь процессов, пославших сообщение, и активизирует процесс из очереди процессов, ждущих сообщение. Активизированный процесс считывает сообщение и активизирует процесс, пославший его.
Такой способ обмена сообщениями, когда передающий процесс блокируется, пока его сообщение не будет принято принимающим процессом, называется РАНДЕВУ. Этот механизм реализован в языке АДА.