- •Глава 6 Проектирование параллельных взаимодействующих вычислительных процессов
- •Независимые и взаимодействующие вычислительные процессы
- •Средства синхронизации и связи при проектировании взаимодействующих вычислительных процессов
- •1 На наш взгляд, эта работа Дейкстры очень полезна с методической точки зрения. Она позволяет понять наиболее тонкие моменты в этой проблематике.
- •Возможные проблемы при организации взаимного исключения посредством использования только блокировки памяти
- •Var перекл : integer:
- •Van перекл1.Перекл2.: boolean: begin nepewil:-false;
- •Алгоритм Деккера
- •Синхронизация процессов посредством операции «проверка и установка»
- •1 Cf (carry flag) — флаг переноса. Располагается в слове состояния программы. Для процессоров i80x86 этот регистр — управляющий регистр cro.
- •Семафорные примитивы Дейкстры
- •Мьютексы
- •Пример простейшей синхронизации взаимодействующих процессов
- •Решение задачи «читатели — писатели»
- •Мониторы Хоара
- •Почтовые ящики
- •1 Название «почтовый ящик» происходит от обычного приспособления для отправки почты.
- •Очереди сообщений
- •Примеры создания параллельных взаимодействующих вычислительных процессов
- •Пример создания многозадачного приложения с помощью системы программирования Borland Delphi
- •Пример создания комплекса параллельных взаимодействующих программ, выступающих как самостоятельные вычислительные процессы
Очереди сообщений
Очереди сообщений (Queue) являются более сложным методом связи между взаимодействующими процессами по сравнению с каналами. С помощью очередей также можно из одной или нескольких задач независимым образом посылать сообщения некоторой задаче-приемнику. При этом только процесс-приемник может читать и удалять сообщения из очереди, а процессы-клиенты имеют право лишь помещать в очередь свои сообщения. Таким образом, очередь работает только в одном направлении. Если же необходима двухсторонняя связь, то можно создать две очереди.
Работа с очередями сообщений имеет много отличий от работы с конвейерами. Во-первых, очереди сообщений предоставляют возможность использовать несколько дисциплин обработки сообщений:
Q FIFO — сообщение, записанное первым, будет первым и прочитано; Q LIFO — сообщение, записанное последним, будет прочитано первым; О приоритетный — сообщения читаются с учетом их приоритетов; Q произвольный доступ, то есть можно читать любое сообщение, тогда как канал обеспечивает только дисциплину FIFO.
Во-вторых, если при чтении сообщения из канала (конвейера) оно удаляется из него, то при чтении сообщения из очереди этого не происходит, и сообщение при желании может быть прочитано несколько раз.
В третьих, в очередях присутствуют не непосредственно сами сообщения, а только их адреса в памяти и размер. Эта информация размещается системой в сегменте памяти, доступном для всех задач, общающихся с помощью данной очереди.
Каждый процесс, использующий очередь, должен предварительно получить разрешение на использование общего сегмента памяти с помощью системных запросов API, ибо очередь — это системный механизм и для работы с ним требуются системные ресурсы и, соответственно, обращение к самой ОС. Во время чтения из очереди задача-приемник пользуется следующей информацией:
Q идентификатор процесса (PID — process ID), который передал сообщение;
Q адрес и длина переданного сообщения;
Q ждать или нет, если очередь пуста;
О приоритет переданного сообщения;
Q номер освобождаемого семафора, когда сообщение передается в очередь.
Наконец, приведем перечень основных функций, управляющих работой очереди (без подробного описания передаваемых параметров), поскольку в различных ОС обращения к этим функциям могут существенно различаться:
Q CreateQueue — создание новой очереди;
О OpenQueue — открытие существующей очереди;
Q ReadQueue — чтение и удаление сообщения из очереди;
Q PeekQueue — чтение сообщения без его последующего удаления из очереди;
Q WriteQueue — добавление сообщения в очередь;
Q CloseQueue — завершение использования очереди;
Q PurgeQueue — удаление из очереди всех сообщений;
Q QueryQueue — определение числа элементов в очереди.
4
Примеры создания параллельных взаимодействующих вычислительных процессов
В завершение данного раздела рассмотрим учебный пример, в котором ставится задача создания комплекса параллельно выполняющихся взаимодействующих программ. Пример не будет иметь содержательного смысла в том плане, что никакой полезной работы программные модули, взаимодействующие между собой, не выполняют. Они только синхронизируют друг друга по предопределенной
схеме, демонстрируя главным образом способы организации взаимодействующих вычислений — взаимное исключение при выполнении критических интервалов, обмены синхросигналами и данными.
Пусть в нашем примере каждая программа (при своем исполнении либо как самостоятельный вычислительный процесс, либо как задача) должна сообщить время начала своей работы, время окончания работы и, возможно, имена тех программ, которые она (при определенных условиях) должна будет запланировать на выполнение.
Для иллюстрации различий в организации взаимодействия полноценных вычислительных процессов и многозадачных (многопотоковых) приложений приведем два примера реализации, что позволит увидеть разные механизмы.
Начнем с более простого случая, когда создается обычное мультитредовое приложение, причем воспользуемся не средствами API, а методами, специально созданными для системы программирования. Второй пример будет иллюстрировать применение более мощных средств для организации взаимного исключения и обмена сообщениями; здесь будут использованы средства самой ОС.
