309
• главная процедура (строки 80 - 84);
• задача-производитель (строки 2 - 17);
• задача-потребитель (строки 18 - 33);
• задача-сервер (строки 34 - 79), обеспечивающая обмен
производителя и потребителя с буфером.
Главная процедура запускает три другие задачи оператором
initiate (строка 83) и переходит в ожидание. Она завершится, когда
завершатся все запущенные ею задачи. Задачи PRODUCER и CONSUMER не
имеют операторов приема, поэтому их спецификации (строки 2 - 4 и 18 -
20) вырожденные – пустые. Тела этих задач содержат простые
бесконечные циклы (loop), в которых выполняется подготовка или
обработка порции и обращение к соответствующей входной точке сервера.
Задача SERVER является аналогом монитора. В ее спецификации (строки
34 - 39) описаны две входные точки: GETPORTION и PUTPORTION. Сам
буфер является локальным в теле сервера (строка 43), также локальны и
индексы чтения и записи (строки 45, 46) и счетчик порций (строки 48 - 49).
Выполнение сервера представляет собой бесконечный цикл (строки 51 -
77), в каждой итерации которого обрабатывается одно обращение.
Оператор select (строки 52 - 75) обеспечивает выбор из обращений:
GETPORTION или PUTPORTION. В зависимости от значения счетчика
PORTCNT из числа альтернатив может исключаться GETPORTION – если
буфер пуст или PUTPORTION – если он полон. Если к началу очередной
итерации обращений нет или есть обращение, которое не позволяет
принять защита when, сервер ожидает. Обратите внимание на
операторные скобки do ... end, следующие за операторами accept
(строки 57 - 60 и 68 - 71). Они ограничивают критическую секцию.
Выполнение процесса-передатчика не возобновится до тех пор, пока
процесс-приемник не выйдет из критической секции. Мы включили в