Язык Ада, 07 лекция (от 07 апреля)
Материал из eSyr's wiki.
Содержание |
Защищенные записи
У механизма есть недостаток: если вспомнить пример буфера, то всем хорош буфер, но плохо то, что буфер оказался процессом, что подразумевает дополнительные накладные расходы, за ним нужно программисту следить(например, для завершения этого процесса вообще). Для решения можно использоваться структуры данных с применением защищенных записей(protected records). Подобно задачам, защищенные записи могут быть как единичными, так и типами данных, которыми можно делать много экземпляров. Защищенная запись – программный модуль с одной стороны, объект данных – с другой. У этого программного модуля есть спецификация и тело. Спецификация описывает интерфейс с внешним миром и состоит она из двух частей. Первая часть начинается со слова protected, после чего идет описание интерфейса, далее идет ключевое слово private, в котором присутствует собственно описание данных. То, что идет от private и до конца, выглядит как обычная запись и является по сути обычной записью: набор полей, каждое поле имеет уникальное имя, оно имеет какой-то тип. В интерфейсе есть операции доступа к этим типа данных. Операции бывают 3 видов: процедуры, функции и входы. Опишем разделяемую переменную – переменную, доступ к которой имеют больше 1 процесса – с помощью защищенных записей. Общие правила: читать значение разделяемой переменной одновременно могут сколько угодно процессов, но при этом нельзя изменять значение переменной. Изменять может только один процесс, и когда изменяется значение переменной, считывать ее нельзя до окончания изменений. Одновременно для каждого защищенного объекта может вызываться сколько угодно функций, тк функции по определению могут только иметь доступ к защищенным данным только по чтению. Одновременно может вызваться ровно одна процедура или вход, тк они могут менять защищенные данные, и при этом не могут выполняться никакие функции. Если вокруг защищенного объекта существует много процессов, то будет выбран произвольный процесс в тот момент, когда объект освободится. С каждым входом ассоциируются очереди вызовов. Объект находится в состоянии, когда он готов воспринимать внешнее воздействие, происходит вызов входа. Он проникает внутрь, объект закрывается от внешнего мира, внутри происходит следующее: для входа проверяется барьерное ограничение. Барьерное ограничение, как правило, зависит от самой записи, т.е. от значения полей. Барьерному ограничению запрещено зависеть от формальных параметров входа. Если барьерное ограничение истинно, то отрабатывает тело входа и по новому проверяются для всех входов значения барьерных ограничений, отбираются те входы, где они истины, и смотрится, есть ли входы в очереди. Если есть, то берем первого из очереди. Если барьер для вызова входа ложный, то вход становится в очередь, и снова перевычисляются барьеры. Все это время объект закрыт от внешнего мира, пока этот барьер не отработает, т.е. не дойдет до того состояния, когда нет непустой очереди к какому-то входу с истинным барьером.
Реализация семафоров как языкового средства (несистемная реализация)
Заводим тип семафор, который может защищать произвольное количество процессов, но при создании экземпляра этого типа будет явно указывать, сколько процессов будет защищать семафор. У семафора есть возможность захватать в монопольное пользование, вернуть ресурс и функция, показывающая, сколько текущих ресурсов осталось. Семафоры могут иметь дискриминанты. В этом типе присутствует 3 вида защищенных операций. Захватить ресурс – может придется подождать, для того, чтобы освободить ресурс, ждать не надо, а читать количество ресурсов могут сколько угодно процессов.
Реализация сигналов как языкового средства (несистемная реализация)
Реализация сигнала, который может быть получен только одним другим процессом. Сигнал можно ждать, сигнал можно послать. Ждать реализуется как вход, послать сигнал реализуется как процедура. Во входе ЖДАТЬ СИГНАЛ булевская переменная будет показывать, есть сигнал или нет. Барьер устанавливается как ЕСТЬ СИГНАЛ. Если сигнал был послан 10 раз, а потом кто-то его наконец дождался, то первые 9 сигналов пропали впустую. Реализация сигнала, который получают сразу все, кто данных сигнал ждет. Ждать сигнал, послать сигнал реализуются как входы. В приватной части тоже объявлен вход reset(обновить). Снова булевская переменна будет показывать, есть ли сигнал. Пусть есть много желающих получить сигнал. У входа wait стоит большая очередь, тк барьерное ограничение – ложь. Пусть нашелся процесс, отправивший сигнал. Вызов входа сигнала начался обрабатываться. Если сигнал никому не нужен, то сигнал отрабатывает и уходит. Если очередь есть, то устанавливается булевский флажок как истина и происходит перенаправление вызова одного входа к другому, т.е. происходит как бы вызов входа reset. Там вызов входа сигнал застревает, тк очередь не пуста. Происходит перевычисление барьеров. Все из очереди ждущих сигнал, будут запущены. В конце отпускается тот процесс, который изначально принял сигнал. Можно реализовать такой же сигнал, но проще. Используются только 2 входа ЖДАТЬ и ПОСЛАТЬ, приватная часть не используется, тк прятать нечего, булевской переменной тоже нет. Тела входов пустые, для них определены только барьеры. Если сигнал был послан, когда никому не нужен, то сигнал пропал. Если есть некоторое количество процессов, ждущих сигнал, то длина очереди будет больше 0 и барьерное условие wait выполнится. Когда надеется тот, кто послал сигнал, то он проверяет барьерное условие, что очередь должна быть пуста, а она не пуста, тут он застревает, перевычисляются барьеры, очередь потихоньку рассасывается и в конце барьерное условие на ПОСЛАТЬ выполняются и сигнал заканчивается.
Асинхронные процессы. Что осталось за кадром
• Управление приоритетами процесса • Задачные и защищенные типы: как из них делать элементы структур данных • Набор ограничений на Адовсикий параллелизм • И др.