740 likes | 957 Views
Ада-технологии - terra incognita для индустрии и образования. Рыбин Сергей Игоревич НИВЦ МГУ, Москва, Россия AdaCore, Paris, France rybin@adacore.com. ( Очередная ) попытка разорвать порочный круг:. Отсутствует «заказ» на подготовку специалистов, владеющих Ада-технологиями.
E N D
Ада-технологии - terra incognita для индустрии и образования Рыбин Сергей Игоревич НИВЦ МГУ, Москва, Россия AdaCore, Paris, France rybin@adacore.com
(Очередная) попытка разорвать порочный круг: Отсутствует «заказ»на подготовку специалистов,владеющихАда-технологиями Ада (практически)отсутствует в современнойроссийской ИТ-индустрии Ада (практически)отсутствует в современномроссийском ИТ-образовании Российские ИТ-специалистыне знакомы с Ада-технологиямии инструментарием
Цели лекции • Показать, что Ада-технологии существуют и являются существенной компонентой современной программной индустрии; • Показать, что в Аде есть интересного и полезного, чего нет в других технологиях; • Целью ни в коей мере не являются: • научиться программировать на Аде; • вдаваться в детали и подробности; • рассмотреть все интересные и полезные возможности языка
Общий план лекции • Что такое Ада - рекламно-пропагандистский обзор (аудитории предлагается верить лектору на слово). • Как язык может помогать писать надежный код и мешать ошибаться? • Параллелизм, системы реального времени, асинхронные процессы – реализация привычной нам модели многопроцессного асинхронного мира высокоуровневыми конструкциями Ады. • Где про это можно почитать, как и что можно взять, чтобы попробовать?
Что такое Ада? • Язык программирования, определяемый стандартом ISO Ada Reference Manual, ISO/IEC 8652:2007(E) Ed. 3; • Язык, первоначально разработанный в конце 70-х годов прошлого века по заказу министерства обороны США для использования в качестве единого языка военных встроенных систем; • Язык, применяемый в настоящее время для разработки больших, долго живущих систем реального времени с повышенными требованиями к надежности; • Язык, практически неизвестный современным российским инженерам и программистам ;
МИФЫ: Ада - мертвый язык, некогда популярный, но сейчас практически не используемый Ада - язык, предназначенный исключительно для военных встроенных систем И РЕАЛЬНОСТЬ: Ада всего лишь отсутствует на рынке «коробочных» продуктов, однако язык активно применяется, в частности, для разработки больших систем реального времени с повышенными требованиями к надежности Последняя версия стандарта Ады принята в 2007 году Число гражданских применений Ады сопоставимо с применениями в военной сфере Ада - не менее универсальный язык, чем С/С++ или Java. Современное состояние Ада-технологий -
МИФЫ: Ада - слишком большой и тяжелый язык для использования в небольшом проекте Ада-технологии неэффективны (трансляторы требуют огромных ресурсов, порождаемый код отличается большим объемом и низкой скоростью исполнения и т.п.) И РЕАЛЬНОСТЬ: Стандарт С++ превосходит стандарт Ады и по объему описания, и по сложности, тогда как Ада превосходит С++ по выразительным средствам Практически на каждой Ада-конференции присутствует робот Lego, управляемый Ада-программой Все современные индустриальные реализации современных индустриальных языков сопоставимы по эффективности (легко проверяется на практике) Современное состояние Ада-технологий -
МИФЫ: Ада-технологии слишком дороги В России нет специалистов, знающих Аду, а подготовка таких специалистов потребовала бы слишком больших затрат И РЕАЛЬНОСТЬ: Существуют полноценные БЕСПЛАТНЫЕ версии Ада-технологий (в частности, специально предназначенные для обучения) В России есть достаточное число Ада-энтузиастов, которые могут стать «точками кристаллизации» соответствующих коллективов разработчиков (http://www.ada-ru.org) Обучение Аде немногим сложнее обучения Паскалю и существенно проще обучения С++ Программист, знающий Паскаль (базовый язык российского ИТ-образования!), в состоянии освоить Аду в объеме, необходимом для начала практической работы, за неделю Современное состояние Ада-технологий -
Ада в мировой программной индустрии • http://www.adacore.com/home/company/customers/ - пользователи системы программирования GNAT • ABB • Alcatel Space • Air Traffic Control Netherlands • Belgocontrol • Boeing • BAE Systems • Ericsson Microwave System • Eurocontrol • Eurocopter • Eurotunnel • General Dynamics • Harris Corporation • Havelsan • Hewlett-Packard • Honeywell • Indra • Kongsberg Defense • Lockheed Martin • MBDA • Ministry of Defense, the Netherlands • NATO • Paranor • Philips Semiconductors ITEC • PostFinance • Raytheon • Rockwell Collins • Saab • Selex Sistemi Integrati • Siemens Transportation Systems • SGI • Thales • ...
Преимущества Ады для индустрии: • Единственный язык, специально созданный для повышения надежности программного кода (при разработке и сопровождении больших долго живущих систем); • Универсальность (язык может все, что могут другие индустриальные языки, и еще кое-что сверх этого); • Стандартизация и отсутствие диалектов; • Реальная кросс-платформенность; • Поддержка кросс-технологий; • Возможность непосредственного доступа к «железу»; • Возможность многоязыкового программирования; • Простота (при прочих равных условиях); • Производительность (при прочих равных условиях);
Язык программирования и надежность. • Ада была создана как средство преодоления кризиса в разработке ПО по заказам Пентагона, который готов был разразиться в 70-е годы прошлого века, причина кризиса – в катастрофическом падении надежности как вновь создаваемых систем, так и модификаций существующих систем в ходе их сопровождения; • Язык был разработан на основе систематической процедуры на основе перечня требований, основным из которых было требование по обеспечению надежности кода как в ходе его создания, так и в процессе сопровождения;
Основные методы обеспечения надежности • Ясный и надежный синтаксис: • программу один раз пишут и бесконечно много раз читают; • работа программиста в индустрии более чем на 90% состоит в изучении и модификации не им написанного кода; • Комфорт и удобство разработчика: • готовые и удобные решения для часто встречающихся технологических потребностей; • удобные средства создания проблемно-ориентированных абстракций; • высокая производительность на полном жизненном цикле программной услуги; • Болезнь легче предупредить, чем лечить: • если требования к результатам деятельности критичны, деятельность должна быть жестко регламентирована, регламент призван уменьшить число ошибок (все, что явным образом не разрешено – запрещено!); • язык должен мешать ошибаться при создании кода; • чем раньше обнаружится ошибка, тем проще и дешевле ее устранение;
Основные методы обеспечения надежности • Классификация ошибок в программе на уровне стандарта языка. Стандарт явно определяет: • нарушение каких сформулированных в нем правил должны обнаруживаться при компиляции модуля; • нарушение каких правил должно обнаруживаться при сборке программы из отдельно компилируемых модулей; • нарушение каких требований должно приводить к возбуждению предопределенного исключения во время выполнения; • какие правила реализация не обязана проверять; • Стандартизация языка при наличии средств контроля стандарта (если программа неправильна – то ни одна реализация ее не скомпилирует и не соберет в исполняемый модуль!)
“Hello, World!” • Ада – прямой потомок Паскаля: with Ada.Text_IO; procedure Hello_World is begin Put_Line (“Hello, World!”); end Hello_World;
Синтаксис и надежность • Опасность ошибиться и не заметить: Си - правильный код: if (the_signal == clear) { open_gates (...); start_train (...); } Но если перепутать “= “и “==“, получим формально корректный код: if (the_signal = clear) { open_gates (...); start_train (...); } В Аде такое невозможно: if The_Signal = Clear then Open_Gates (...); Start_Train (...); end if; В Аде присваивание “:=“ никогда не может оказаться частью конструкции, являющейся условием и быть перепутано со сравнением “=“. В Аде операторы четко отделены от выражений.
Синтаксис и надежность • Опасность ошибиться и не заметить: Си - правильный код: if (the_signal == clear) { open_gates (...); start_train (...); } Если случайно поставить «лишнюю» точку с запятой, получим формально корректный код: if (the_signal == clear) ; { open_gates (...); start_train (...); } В Аде такое невозможно: if The_Signal = Clear then ; Open_Gates (...); Start_Train (...); end if; В Аде не бывает неявных пустых операторов, которые «вдруг» появляются перед “;”.Данный код будет отвергнут как синтаксически некорректный
Синтаксис и надежность • Полезные «мелочи» procedureP1is ... procedureP2is ... begin ... endP2; begin ... Bl1 : begin ... Bl2 : begin ... endBl2; ... endBl1; endP1; record I : Integer; end record; ... ifCondition then for I in 1 .. 10loop caseValue is ... end case; end loop; end if;
Прогнозирование и контроль. • Прогнозирование и контроль свойств элементов программы - основное средство обеспечения надежности: • каждая используемая в программе сущность должна быть объявлена; • объявление полностью определяет свойства сущности; • каждая сущность может использоваться только в соответствии с ее свойствами, заданными в ее объявлении; • никакие неявные преобразования или изменения свойств сущности недопустимы; • Все, что не разрешено (объявлением сущности), запрещено (при использовании сущности);
Строгая типизация в Аде -философия • Что такое тип данных в языке программирования? • множество значений + набор применимых операций или все-таки • отражение содержательной роли объектов данных в проблемной области? • Типы данных и надежность программ - философия Ады: • надежность программы возрастает, если программа максимально точно и подробно отражает модель проблемной области; • для каждого объекта данных важно определить его роль в (модели) проблемной области и проконтролировать, что каждый объект используется только в своей роли; • Концепция строгой типизации:тип данных = содержательная роль объектов данных в модели проблемной области;
Строгая типизация в Аде - теория • Все типы данных явно определены (объявлены) в программе, все они имеют имена и определения; • Все объекты данных (и все их компоненты) имеют ровно один тип. Этот тип известен при объявлении объекта. Этот тип должен быть задан путем указания имени ранее объявленного типа данных; • Все операции объявлены в тексте программы, все они имеют явно определенные типы параметров и результата (если он есть) Эти типы также должны быть заданы путем указания имен ранее объявленных типов данных. • При вызове любой операции (присваивание тоже считается операцией!) проверяется, что типы операндов соответствуют заявленным типам параметров операции; • Соответствие типов есть не соответствие структур значений, а совпадение имен (объявлений) типов; • Все типы должны определяться статически (это никак не связано и никак не препятствует динамическому полиморфизму как части объектно-ориентированного программирования, далее мы рассмотрим динамический полиморфизм подробнее) • Неявные преобразования типов недопустимы.
Строгая типизация в Аде – классический пример typeФрукты is new Integer; -- тип с теми же свойствами, что -- Integer, но ДРУГОЙ!!! typeЯблоки is newФрукты; typeАпельсины is newФрукты; ... Я1, Я2 : Яблоки; А1, А2 : Апельсины; Ф: Фрукты; ... Я1 := 5; -- можно Я1 := Я1 + Я2; -- можно А1 := Я1 + А2; -- нельзя - нет такого «+»! Ф := Я1; -- нельзя - разные типы источника и получателя «:=»! if Я1 + Я2 > Ф then-- и это недопустимо!Нет такого “>” … end if;
Строгая типизация в Аде – смена содержательной роли объекта • Совсем строгая типизация на практике оказывается обременительной - иногда объекту данных надо в каком-то случае выступить в иной содержательной роли; • Смена содержательной роли объекта данных не должна происходить сама собой, это должно быть осознанным действием программиста; • Смена содержательной роли объекта должна быть локализована и легко заметна в тексте программы; • Механизм явного преобразования типов
Производные типы и преобразование типа Фрукты type Фруктыis new Integer; type Яблокиis new Фрукты; type Апельсины is new Фрукты; type Антоновкаis new Яблоки; type Зеленая_Антоновка is new Антоновка; type Желтая_Антоновка is new Антоновка; Я : Яблоки; Я_Антоновка : Антоновка; Ж_Антоновка : Желтая_Антоновка; З_Антоновка : Зеленая_Антоновка; А : Апельсины; Ф: Фрукты; ... Я_Антоновка := Антоновка (Ж_Антоновка) + Антоновка (З_Антоновка); Я := Яблоки (З_Антоновка) + Я; Ф := Фрукты (А) + Фрукты (Ж_Антоновка); А := Апельсины (Я); if Яблоки (Ж_Антоновка) + Яблоки (З_Антоновка ) > Яблоки (А) then ... end if; Яблоки Апельсины Антоновка Зеленая_Антоновка Желтая_Антоновка
«Если нельзя, но очень хочется, то можно!» • Иногда возникает необходимость преобразования типа между типами, вообще не имеющими друг к другу никакого отношения… • Это можно сделать, но для этого придется специально настроить вот такой шаблон: generictype Source(<>) islimitedprivate;type Target(<>) islimitedprivate;function Ada.Unchecked_Conversion(S : Source) return Target; и применить результат настройки к нужным объектам (то есть, сделать такое случайно, «не заметив», невозможно).
Все намерения программиста должны быть явно обозначены type Week_Day is (Mon, Tue, Wen, Thu, Fri, Sat, Sun); Day : Week_Day; ... case Day is when Mon .. Thu => Working_Like_Dog; when Sat => Drinking; when Sun => Fishing; end case; -- Но что происходит в пятницу??? -- Такой код не будет скомпилирован! Статическая борьба с «дохлыми» ссылками: package P is type T is ...; type T_Ptr is access all T; Global : T_Ptr; end P; ... procedure Q is X : aliased T; Local : T_Ptr := X'Access;-- Так нельзя! --Local может быть присвоен чему угодно, -- в т.ч. и Global begin Global := X'Access;-- Нельзя! Global := Local;-- Нельзя! Global := X’Unchecked_Access; -- Можно, но под личную -- ответственность автора ... end Q; Полезные «мелочи»…
Подтипы и исключительные ситуации • Тип данных – это: • концептуально - содержательная роль объектов данных в программе; • технически – множество значений + совокупность операций; • Подтип – это ограничение множества значений в рамках той же содержательной роли; • Реализация сама проверяет, что присваиваемое значение попадает в подтип, определенный для данного объекта данных (принадлежит подтипу); • В случае нарушения подтипового ограничения при выполнении программы возбуждается предопределенное ограничение Constraint_Error;
Подтипы - пример procedure Автопилотis type Скорость is digits 8 range 0.0 .. 500.0; function Данные_Спидометра return Скоростьis ... end Данные_Спидометра; subtype Безопасная_Скорость is Скорость range 0.0 .. 200.0; Текущая_Скорость : Безопасная_Скорость; ... begin ... loop Текущая_Скорость:= Данные_Спидометра; ... end loop; ... exception when Constraint_Error => Включить_Аварийный_Сигнал; Нажать_На_Тормоз; ... end Автопилот;
Подтипы и исключительные ситуации • Для одного типа данных можно определить сколько угодно разных подтипов; • Подтиповые ограничения формулируются статически, но определяются и проверяются – динамически subtypeБезопасная_Скорость isСкоростьrange Min (Режим_Полета) .. Max (Режим_Полета); • Подтипы можно применять при конструировании сложных структур данных; • Существуют различные виды ограничений; • Подтиповые ограничения всегда проверяются динамически;
package P1 is function F1 return Integer; end P1; with P1; package body P2 is X2 : Integer := P1.F1; function F2 return Integer is begin return X2; end F2; end P2; Проблемы при сборке программы package P2 is function F2 return Integer; end P2; with P2; package body P1 is X1 : Integer := P2.F2; function F1 return Integer is begin return X1; end F1; end P1; Реализация Ады обязана определить, что не существует корректного порядка включения кода, порождаемого модулями P1 и P2, в исполняемый код, а потому никогда не будет создан исполняемый код для программы, в состав которой входят эти модули.
На обеспечение надежности работают и такие языковые механизмы, как: • Разделение спецификации (интерфейса) и реализации (тела) для каждого программного модуля и невозможность доступа к телам со стороны клиентов модуля; • Приватные типы; • Правила видимости имен; • Правила раздельной компиляции; • Контрактная модель настройки шаблонов; • …
Чего стоят такие меры обеспечения надежности? • Статический контроль (как при раздельной компиляции модулей, так и при сборке программ) приводит только лишь к утяжелению транслятора, никак не сказываясь на размерах и быстродействии исполняемого кода; • Динамический контроль (подтиповые ограничения) незначительно утяжеляют исполняемый код, при необходимости они могут быть (выборочно) отключены;
И что они дают? IEEE Software, 1987, #1, pp40-44: • производительность разработчиков на полном цикле (>= 20_000 SLOC): • Ада - 12 строк/день • другие языки - 10 строк/день • распределение затрат в проекте:
Асинхронные процессы в Аде • Наш мир состоит из взаимодействующих асинхронных процессов, следовательно, программы, встроенные в реальный мир и управляющие реальными процессами, должны уметь работать с асинхронными процессами; • Взаимодействие асинхронных процессов – сложное явление; • Программы с асинхронными процессами существенно сложнее последовательных программ; • Чем может помочь язык программирования? • Предоставление высокоуровневых средств описания асинхронных процессов и управления ими; • Данные средства должны быть согласованы с привычными нам моделями взаимодействия асинхронных процессов; • Данные средства должны быть ориентированы на устойчивые к ошибкам парадигмы и технологии работы с асинхронными процессами;
Определение асинхронного процесса. • Асинхронному процессу соответствует специальный программный модуль – задача (task); • Запуск, завершение и взаимодействие процессов управляется языковыми конструкциями и правилами, не требуется никаких обращений к каким-либо библиотекам (никаких spawn, fork и тому подобного);
Два асинхронных процесса на 20 строк кода результатработы этой программы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Terminating 1with Ada.Text_IO; 2 procedure Tasking_Example is 3 Finished : Boolean := False; 4 pragma Atomic(Finished); 5 6 task Outputter; -- task specification 7 8 task body Outputter is-- task body 9 Count : Integer := 1; 10 begin 11 while not Finished loop 12 Ada.Text_IO.Put_Line(Integer'Image(Count)); 13 Count := Count + 1; 14 delay 1.0; -- one second 15 end loop; 16 Ada.Text_IO.Put_Line("Terminating"); 17 end Outputter; 18 19 begin 20 delay 20.0; -- twenty seconds 21 Finished := True; 22 end Tasking_Example; процессTasking_Example процессOutputter
Задачи - интерфейс • Каждый программный модуль в Аде состоит из спецификации, описывающей интерфейс модуля с внешним миром, и тела, описывающего внутреннее устройство/семантику/поведение модуля; • Интерфейс (спецификация) модуля-задачи может содержать только объявления входов; • Для внешнего мира вход задачи выглядит как процедура – он может иметь параметры, его можно вызвать; • В теле задачи каждому входу этой задачи должен соответствовать оператор приема входа (accept), который выполняется при вызове входа задачи (в момент рандеву);
task T1 is entry E1 (X : in Some_Type); end T1; task body T1 is Var1 : Some_Type; ... begin ... accept E1 (X : in Some_Type) do Var1 := X; end E2; ... ... T2.E2; ... ... ... end T1; task T2 is entry E2; end T2; task body T2 is Var2 : Some_Type; ... begin ... ... ... T1.E1 (Var2); ... ... ... accept E2; ... ... end T1; Рандеву как средство синхронизации и обмена данными ждет вызова ждетприема рандеву ждетприема ждет вызова рандеву
Асимметричное рандеву как модель поведения «клиент-мастер» • Рандеву - вызывающая задача в точке вызова входа и вызываемая в точке приема вызова должны оказаться одновременно; • Вызывающая задача знает, вход какой именно задачи она вызывает (имя входа доступно только в префиксной форме, префикс - имя задачи, которой принадлежит вход), вызываемая - не знает, кто именно ее вызвал, лишь бы параметры были соответствующих типов - поэтому рандеву асимметричное; • Модель поведения «клиент-мастер»: у клиента есть часы, он хочет их починить и выбирает именно часовую мастерскую, часовому мастеру все равно, кто именно к нему пришел, лишь бы принес чинить часы, а не холодильник. • К одному и тому же мастеру могут выстраиваться очереди клиентов - ожидающие рандеву очереди вызовов входов, выполнение оператора приема для данного входа отпускает из очереди первый вызов; • Пока задача ждет, чтобы ее вызов входа обслужили (или чтобы ее вход вызвали), она просто стоит на месте;
Взаимодействие асинхронных процессов • Описать отдельно взятый процесс относительно просто, основная сложность – во взаимодействии процессов: • совместное использование несколькими процессами одного и того же ресурса (разделяемые ресурсы); • взаимное исключение (в каждый момент времени ресурсом может пользоваться не более одного процесса); • «тупики»; • Внешняя и внутренняя дисциплины использования разделяемых ресурсов: • кто и где следит за тем, чтобы разделяемый ресурс использовался корректно – сам ресурс или нечто (некто?) вне его?
Взаимодействие асинхронных процессов: Адский подход • Процесс должен уметь выбирать варианты своего поведения в зависимости от своего состояния и готовности других процессов к взаимодействию с ним; • Средства управления взаимодействием процессов ориентированы на внутреннюю дисциплину использования разделяемых ресурсов как на более надежную: • разумно устроенный разделяемый ресурс допускает только корректное использование! • Каждый процесс проектируется в предположении, что мир, с которым он взаимодействует, устроен разумно, и все, что от него требуется – гарантировать разумность своего собственного поведения (процесс сам может для кого-то оказаться разделяемым ресурсом!);
Постановка задачи «взаимодействие через буфер» • Из внешней среды поступают однородные объекты (сообщения), с каждым из которых необходимо проделать два разных действия – анализ и синтез. Анализ и синтез выполняются независимо для разных объектов, для одного и того же объекта анализ следует за синтезом. При этом существенными являются временные характеристики: • минимальное время между поступлением сообщений – τ • максимальное время анализа – τ – ε, где ε << τ • максимальное время синтеза - 3 τ, среднее время синтеза τ – ε1, где ε1 << τ Анализ Синтез внешняясреда сообщение ответ внешняясреда
Точка зрения пользователя (внешней среды) - надо иметь возможность по мере необходимости передавать сообщение, а по мере готовности - получать ответ Эти действия независимы и могут происходить асинхронно package Анализ_Синтез is type Сообщение is array (1 .. 80) of Character; type Ответ is new Сообщение; task Анализ is entry Принять (X : in Сообщение); end Анализ; task Синтез is entry Выдать (X : out Ответ); end Синтез; end Анализ_Синтез; Решение - интерфейс
package Генератор_Сообщений is task Генератор is entry Start; end Генератор; end Генератор_Сообщений; package Потребитель_Сообщений is task Потребитель is entry Start; end Потребитель; end Потребитель_Сообщений ; with Генератор_Сообщений; withПотребитель_Сообщений; ... procedure Main is Ch : Character; begin Генератор_Сообщений.Генератор.Start; Потребитель_Сообщений.Потребитель.Start; ... end Main; -- Мы не рассматриваем проблему -- завершения задач! with Анализ_Синтез; use Анализ_Синтез; package body Генератор_Сообщений is task body Генератор is Message : Сообщение; begin accept Start; loop Message := Сформировать_Сообщение (...); Анализ.Принять (Message); end loop; end Генератор; end Генератор_Сообщений; with Анализ_Синтез; use Анализ_Синтез; package body Потребитель_Сообщений is task body Потребитель is Answer : Ответ; begin accept Start; loop Синтез.Выдать (Answer); Использовать_Ответ (Answer); end loop; end Потребитель; end Потребитель_Сообщений; Решение - как им пользоваться?
Реализация взаимодействием через буфер Анализ.Принять Синтез. Выдать ответ Потребитель_Сообщений сообщение Генератор_Сообщений разбор разбор интерфейс реализация Буфер
-- Воспользуемся классической -- абстракцией буфера -- ограниченного размера generic Размер : in Positive := 10; type Элемент is private; package Любой_Буфер is procedure В_Буфер (X : in Элемент); procedure Из_Буфера (X : out Элемент); function Пуст return Boolean; function Полон return Boolean; end Любой_Буфер; with Любой_Буфер; package body Анализ_Синтез is typeРазбор is new Сообщение; task Буфер is entry Положить (X : in Разбор); entry Достать (X : out Разбор); end Буфер; task body Анализ is ...; taskbody Синтез is ...; taskbody Буфер is ...; endАнализ_Синтез; Реализация - общая структура Осталось написать тела...
task body Анализ is Моё_Сообщение : Сообщение; Готов : Разбор; begin loop accept Принять (X : in Сообщение) do Моё_Сообщение := X; end Принять; ... -- анализ сообщения, -- формирование значения -- переменной Готов Буфер.Положить (Готов); end loop; end Анализ; task body Синтез is Моё_Сообщение : Разбор; Готов : Ответ; begin loop Буфер.Достать (Моё_Сообщение); ... -- Синтез ответа, -- формирование значения -- переменной Готов accept Выдать (X : out Ответ) do X := Готов; end Готов; end loop; end Синтез; Реализация - тела задач Анализ и Синтез ... в предположении, что Буфер - «умный» и позволяет себя использовать только корректно...
-- подготовка структуры -- данных package Локальный_Буфер is new Любой_Буфер (Размер => 30; Элемент => Разбор); use Локальный_Буфер; task body Буфер is begin loop select when not Полон => accept Положить (X : in Разбор) do В_Буфер (X); end Положить; or when Полонor else (not Пуст and then Положить’Count)= 0 => accept Достать (X : out Разбор) do Из_Буфера (X); end Достать; or terminate; end select; endloop; end Буфер; Реализация «умного» Буфера • охранные ограничения • операторы приема • альтернатива завершения
Семантика оператора отбора • Вычисляются все охранные ограничения (порядок вычисления недетерминирован) и выбираются «открытые» альтернативы приема (охранное ограничение отсутствует или истинно); • Среди «открытых» альтернатив приема выбираются готовые к немедленному рандеву (очереди вызовов соответствующих входов не пусты); • Среди «открытых» и готовых к рандеву альтернатив приема недетерминированным образом выбирается одна и выполняется; • Если нет «открытых» и готовых к рандеву альтернатив приема, выполнение оператора зависит от его завершающей части • если таковой является альтернатива завершения, задача завершается, если она «больше никому не нужна»;
Та же самая задача – на основе внешней дисциплины использования разделяемых ресурсов • Попробуйте решить тут же задачу, если единственным средством организации взаимодействия процессов является семафор… • при помощи семафора несложно обеспечить, чтобы процессы Анализ и Синтез использовали буфер в режиме взаимного исключения, но как обеспечить отсутствие тупиков (процесс Анализ захватил полностью заполненный буфер в исключительное использование)? • как обеспечить приоритет процесса Анализ при использовании буфера?
Альтернатива задержки: если есть «открытые» альтернативы, но нет готовых к рандеву - ждем указанное время. Если за это время не появился подходящий вызов - выполняем операторы альтернативы задержки; Если нам за 0.1 секунды не сообщили новое значение температуры - бьем тревогу! loop select accept Считать_Значение (T : in Temperature) do Текущая_Температура := T; end Считать_Значение; -- анализируем новое -- значение температуры... or delay 0.1; raise Сломался_Градусник; end select; end loop; Разновидности оператора отбора - альтернатива задержки