614ea4119d92eaba1cabe665ee8fd56b.ppt
- Количество слайдов: 74
Ада-технологии - terra incognita для индустрии и образования Рыбин Сергей Игоревич НИВЦ МГУ, Москва, Россия Ada. Core, Paris, France rybin@adacore. com www. adacore. com
(Очередная) попытка разорвать порочный круг: Отсутствует «заказ» на подготовку специалистов, владеющих Ада-технологиями Ада (практически) отсутствует в современном российском ИТ-образовании Ада (практически) отсутствует в современной российской ИТ-индустрии Российские ИТ-специалисты не знакомы с Ада-технологиями и инструментарием 2
Цели лекции • Показать, что Ада-технологии существуют и являются существенной компонентой современной программной индустрии; • Показать, что в Аде есть интересного и полезного, чего нет в других технологиях; • Целью ни в коей мере не являются: – научиться программировать на Аде; – вдаваться в детали и подробности; – рассмотреть все интересные и полезные возможности языка 3
Общий план лекции • Что такое Ада - рекламно-пропагандистский обзор (аудитории предлагается верить лектору на слово). • Как язык может помогать писать надежный код и мешать ошибаться? • Параллелизм, системы реального времени, асинхронные процессы – реализация привычной нам модели многопроцессного асинхронного мира высокоуровневыми конструкциями Ады. • Где про это можно почитать, как и что можно взять, чтобы попробовать? 4
Что такое Ада? • Язык программирования, определяемый стандартом ISO Ada Reference Manual, ISO/IEC 8652: 2007(E) Ed. 3; • Язык, первоначально разработанный в конце 70 -х годов прошлого века по заказу министерства обороны США для использования в качестве единого языка военных встроенных систем; • Язык, применяемый в настоящее время для разработки больших, долго живущих систем реального времени с повышенными требованиями к надежности; • Язык, практически неизвестный современным российским инженерам и программистам ; 5
Современное состояние Ада-технологий МИФЫ: И РЕАЛЬНОСТЬ: • • Ада всего лишь отсутствует на рынке «коробочных» продуктов, однако язык активно применяется, в частности, для разработки больших систем реального времени с повышенными требованиями к надежности • Последняя версия стандарта Ады принята в 2007 году • Число гражданских применений Ады сопоставимо с применениями в военной сфере • Ада - не менее универсальный язык, чем С/С++ или Java. • Ада - мертвый язык, некогда популярный, но сейчас практически не используемый Ада - язык, предназначенный исключительно для военных встроенных систем 6
Современное состояние Ада-технологий МИФЫ: И РЕАЛЬНОСТЬ: • • Стандарт С++ превосходит стандарт Ады и по объему описания, и по сложности, тогда как Ада превосходит С++ по выразительным средствам • Практически на каждой Адаконференции присутствует робот Lego, управляемый Ада-программой • Все современные индустриальные реализации современных индустриальных языков сопоставимы по эффективности (легко проверяется на практике) • Ада - слишком большой и тяжелый язык для использования в небольшом проекте Ада-технологии неэффективны (трансляторы требуют огромных ресурсов, порождаемый код отличается большим объемом и низкой скоростью исполнения и т. п. ) 7
Современное состояние Ада-технологий МИФЫ: И РЕАЛЬНОСТЬ: • • Существуют полноценные БЕСПЛАТНЫЕ версии Ада-технологий (в частности, специально предназначенные для обучения) • В России есть достаточное число Адаэнтузиастов, которые могут стать «точками кристаллизации» соответствующих коллективов разработчиков (http: //www. adaru. org) • Обучение Аде немногим сложнее обучения Паскалю и существенно проще обучения С++ • Программист, знающий Паскаль (базовый язык российского ИТ-образования!), в состоянии освоить Аду в объеме, необходимом для начала практической работы, за неделю • Ада-технологии слишком дороги В России нет специалистов, знающих Аду, а подготовка таких специалистов потребовала бы слишком больших затрат 8
Ада в мировой программной индустрии • 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 • Post. Finance • Raytheon • Rockwell Collins • Saab • Selex Sistemi Integrati • Siemens Transportation Systems • SGI • Thales • . . . 9
Преимущества Ады для индустрии: • Единственный язык, специально созданный для повышения надежности программного кода (при разработке и сопровождении больших долго живущих систем); • Универсальность (язык может все, что могут другие индустриальные языки, и еще кое-что сверх этого); • Стандартизация и отсутствие диалектов; • Реальная кросс-платформенность; • Поддержка кросс-технологий; • Возможность непосредственного доступа к «железу» ; • Возможность многоязыкового программирования; • Простота (при прочих равных условиях); • Производительность (при прочих равных условиях); 10
Язык программирования и надежность. • Ада была создана как средство преодоления кризиса в разработке ПО по заказам Пентагона, который готов был разразиться в 70 -е годы прошлого века, причина кризиса – в катастрофическом падении надежности как вновь создаваемых систем, так и модификаций существующих систем в ходе их сопровождения; • Язык был разработан на основе систематической процедуры на основе перечня требований, основным из которых было требование по обеспечению надежности кода как в ходе его создания, так и в процессе сопровождения; 11
Основные методы обеспечения надежности • Ясный и надежный синтаксис: – программу один раз пишут и бесконечно много раз читают; – работа программиста в индустрии более чем на 90% состоит в изучении и модификации не им написанного кода; • Комфорт и удобство разработчика: – готовые и удобные решения для часто встречающихся технологических потребностей; – удобные средства создания проблемно-ориентированных абстракций; – высокая производительность на полном жизненном цикле программной услуги; • Болезнь легче предупредить, чем лечить: – если требования к результатам деятельности критичны, деятельность должна быть жестко регламентирована, регламент призван уменьшить число ошибок (все, что явным образом не разрешено – запрещено!); – язык должен мешать ошибаться при создании кода; – чем раньше обнаружится ошибка, тем проще и дешевле ее устранение; 12
Основные методы обеспечения надежности • Классификация ошибок в программе на уровне стандарта языка. Стандарт явно определяет: – нарушение каких сформулированных в нем правил должны обнаруживаться при компиляции модуля; – нарушение каких правил должно обнаруживаться при сборке программы из отдельно компилируемых модулей; – нарушение каких требований должно приводить к возбуждению предопределенного исключения во время выполнения; – какие правила реализация не обязана проверять; • Стандартизация языка при наличии средств контроля стандарта (если программа неправильна – то ни одна реализация ее не скомпилирует и не соберет в исполняемый модуль!) 13
“Hello, World!” • Ада – прямой потомок Паскаля: with Ada. Text_IO; procedure Hello_World is begin Put_Line (“Hello, World!”); end Hello_World; 14
Синтаксис и надежность • Опасность ошибиться и не заметить: Си - правильный код: В Аде такое невозможно: if (the_signal == clear) if The_Signal = Clear then { Open_Gates (. . . ); open_gates (. . . ); start_train (. . . ); } Но если перепутать “= “и “==“, получим формально корректный код: if (the_signal = clear) { Start_Train (. . . ); end if; В Аде присваивание “: =“ никогда не может оказаться частью конструкции, являющейся условием и быть перепутано со сравнением “=“. В Аде операторы четко отделены от выражений. open_gates (. . . ); start_train (. . . ); } 15
Синтаксис и надежность • Опасность ошибиться и не заметить: Си - правильный код: В Аде такое невозможно: if (the_signal == clear) if The_Signal = Clear then ; { Open_Gates (. . . ); open_gates (. . . ); start_train (. . . ); } Если случайно поставить «лишнюю» точку с запятой, получим формально корректный код: Start_Train (. . . ); end if; В Аде не бывает неявных пустых операторов, которые «вдруг» появляются перед “; ”. Данный код будет отвергнут как синтаксически некорректный if (the_signal == clear) ; { open_gates (. . . ); start_train (. . . ); } 16
Синтаксис и надежность • Полезные «мелочи» procedure P 1 is. . . procedure P 2 is. . . begin. . . end P 2; begin. . . Bl 1 : begin. . . Bl 2 : begin. . . end Bl 2; . . . end Bl 1; end P 1; record I : Integer; end record; . . . if Condition then for I in 1. . 10 loop case Value is. . . end case; end loop; end if; 17
Прогнозирование и контроль. • Прогнозирование и контроль свойств элементов программы - основное средство обеспечения надежности: – каждая используемая в программе сущность должна быть объявлена; – объявление полностью определяет свойства сущности; – каждая сущность может использоваться только в соответствии с ее свойствами, заданными в ее объявлении; – никакие неявные преобразования или изменения свойств сущности недопустимы; • Все, что не разрешено (объявлением сущности), запрещено (при использовании сущности); 18
Строгая типизация в Аде -философия • Что такое тип данных в языке программирования? – множество значений + набор применимых операций или все-таки – отражение содержательной роли объектов данных в проблемной области? • Типы данных и надежность программ - философия Ады: – надежность программы возрастает, если программа максимально точно и подробно отражает модель проблемной области; – для каждого объекта данных важно определить его роль в (модели) проблемной области и проконтролировать, что каждый объект используется только в своей роли; • Концепция строгой типизации: тип данных = содержательная роль объектов данных в модели проблемной области; 19
Строгая типизация в Аде - теория · Все типы данных явно определены (объявлены) в программе, все они имеют имена и определения; · Все объекты данных (и все их компоненты) имеют ровно один тип. Этот тип известен при объявлении объекта. Этот тип должен быть задан путем указания имени ранее объявленного типа данных; · Все операции объявлены в тексте программы, все они имеют явно определенные типы параметров и результата (если он есть) Эти типы также должны быть заданы путем указания имен ранее объявленных типов данных. · При вызове любой операции (присваивание тоже считается операцией!) проверяется, что типы операндов соответствуют заявленным типам параметров операции; · Соответствие типов есть не соответствие структур значений, а совпадение имен (объявлений) типов; · Все типы должны определяться статически (это никак не связано и никак не препятствует динамическому полиморфизму как части объектноориентированного программирования, далее мы рассмотрим динамический полиморфизм подробнее) · Неявные преобразования типов недопустимы. 20
Строгая типизация в Аде – классический пример type Фрукты is new Integer; -- -type Яблоки тип с теми же свойствами, что Integer, но ДРУГОЙ!!! is new Фрукты; type Апельсины is new Фрукты; . . . Я 1, Я 2 : Яблоки; А 1, А 2 : Апельсины; Ф : Фрукты; . . . -- можно Я 1 : = Я 1 + Я 2; -- можно А 1 : = Я 1 + А 2; -- нельзя - нет такого «+» ! Я 1 : = 5; Ф : = Я 1; if -- нельзя - разные типы источника и получателя «: =» ! Я 1 + Я 2 > Ф then -- и это недопустимо! Нет такого “>” … end if; 21
Строгая типизация в Аде – смена содержательной роли объекта • Совсем строгая типизация на практике оказывается обременительной - иногда объекту данных надо в каком -то случае выступить в иной содержательной роли; • Смена содержательной роли объекта данных не должна происходить сама собой, это должно быть осознанным действием программиста; • Смена содержательной роли объекта должна быть локализована и легко заметна в тексте программы; • Механизм явного преобразования типов 22
Производные типы и преобразование типа Фрукты type Фрукты is new Integer; type Яблоки is new Фрукты; type Апельсины is new Фрукты; type Антоновка is new Яблоки; Яблоки Апельсины type Зеленая_Антоновка is new Антоновка; type Желтая_Антоновка Я is new Антоновка; Антоновка : Яблоки; Я_Антоновка : Антоновка; Ж_Антоновка : Желтая_Антоновка; З_Антоновка : Зеленая_Антоновка; А : Апельсины; Ф : Фрукты; Зеленая_ Антоновка Желтая_ Антоновка . . . Я_Антоновка : = Антоновка (Ж_Антоновка) + Антоновка (З_Антоновка); Я : = Яблоки (З_Антоновка) + Я; Ф : = Фрукты (А) + Фрукты (Ж_Антоновка); А : = Апельсины (Я); if Яблоки (Ж_Антоновка) + Яблоки (З_Антоновка ) > Яблоки (А) then. . . end if; 23
«Если нельзя, но очень хочется, то можно!» • Иногда возникает необходимость преобразования типа между типами, вообще не имеющими друг к другу никакого отношения… • Это можно сделать, но для этого придется специально настроить вот такой шаблон: generic type Source(<>) is limited private; type Target(<>) is limited private; function Ada. Unchecked_Conversion(S : Source) return Target; и применить результат настройки к нужным объектам (то есть, сделать такое случайно, «не заметив» , невозможно). 24
Полезные «мелочи» … • Все намерения программиста должны быть явно обозначены 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; 25
Подтипы и исключительные ситуации • Тип данных – это: – концептуально - содержательная роль объектов данных в программе; – технически – множество значений + совокупность операций; • Подтип – это ограничение множества значений в рамках той же содержательной роли; • Реализация сама проверяет, что присваиваемое значение попадает в подтип, определенный для данного объекта данных (принадлежит подтипу); • В случае нарушения подтипового ограничения при выполнении программы возбуждается предопределенное ограничение Constraint_Error; 26
Подтипы - пример 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 Автопилот; 27
Подтипы и исключительные ситуации • Для одного типа данных можно определить сколько угодно разных подтипов; • Подтиповые ограничения формулируются статически, но определяются и проверяются – динамически subtype Безопасная_Скорость is Скорость range Min (Режим_Полета). . Max (Режим_Полета); • Подтипы можно применять при конструировании сложных структур данных; • Существуют различные виды ограничений; • Подтиповые ограничения всегда проверяются динамически; 28
Проблемы при сборке программы package P 1 is function F 1 return Integer; package P 2 is function F 2 return Integer; end P 1; end P 2; with P 1; package body P 1 is package body P 2 is X 1 : Integer : = P 2. F 2; X 2 : Integer : = P 1. F 1; function F 1 return Integer is function F 2 return Integer is begin return X 1; end F 1; end P 1; return X 2; end F 2; end P 2; Реализация Ады обязана определить, что не существует корректного порядка включения кода, порождаемого модулями P 1 и P 2, в исполняемый код, а потому никогда не будет создан исполняемый код для программы, в состав которой входят эти модули. 29
На обеспечение надежности работают и такие языковые механизмы, как: • Разделение спецификации (интерфейса) и реализации (тела) для каждого программного модуля и невозможность доступа к телам со стороны клиентов модуля; • Приватные типы; • Правила видимости имен; • Правила раздельной компиляции; • Контрактная модель настройки шаблонов; • … 30
Чего стоят такие меры обеспечения надежности? • Статический контроль (как при раздельной компиляции модулей, так и при сборке программ) приводит только лишь к утяжелению транслятора, никак не сказываясь на размерах и быстродействии исполняемого кода; • Динамический контроль (подтиповые ограничения) незначительно утяжеляют исполняемый код, при необходимости они могут быть (выборочно) отключены; 31
И что они дают? IEEE Software, 1987, #1, pp 40 -44: • производительность разработчиков на полном цикле (>= 20_000 SLOC): – – • Ада - 12 строк/день другие языки - 10 строк/день распределение затрат в проекте: 32
Асинхронные процессы в Аде • Наш мир состоит из взаимодействующих асинхронных процессов, следовательно, программы, встроенные в реальный мир и управляющие реальными процессами, должны уметь работать с асинхронными процессами; • Взаимодействие асинхронных процессов – сложное явление; • Программы с асинхронными процессами существенно сложнее последовательных программ; • Чем может помочь язык программирования? – Предоставление высокоуровневых средств описания асинхронных процессов и управления ими; – Данные средства должны быть согласованы с привычными нам моделями взаимодействия асинхронных процессов; – Данные средства должны быть ориентированы на устойчивые к ошибкам парадигмы и технологии работы с асинхронными процессами; 33
Определение асинхронного процесса. • Асинхронному процессу соответствует специальный программный модуль – задача (task); • Запуск, завершение и взаимодействие процессов управляется языковыми конструкциями и правилами, не требуется никаких обращений к каким-либо библиотекам (никаких spawn, fork и тому подобного); 34
Два асинхронных процесса на 20 строк кода 1 2 with Ada. Text_IO; procedure Tasking_Example is 3 Finished : Boolean : = False; 4 pragma Atomic(Finished); процесс Tasking_Example 5 6 task Outputter; -- task specification 7 8 task body Outputter is 9 10 -- task body Count : Integer : = 1; 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 21 delay 20. 0; -- twenty seconds Finished : = True; 22 end Tasking_Example; процесс Outputter результат работы этой программы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Terminating 35
Задачи - интерфейс • Каждый программный модуль в Аде состоит из спецификации, описывающей интерфейс модуля с внешним миром, и тела, описывающего внутреннее устройство/семантику/поведение модуля; • Интерфейс (спецификация) модуля-задачи может содержать только объявления входов; • Для внешнего мира вход задачи выглядит как процедура – он может иметь параметры, его можно вызвать; • В теле задачи каждому входу этой задачи должен соответствовать оператор приема входа (accept), который выполняется при вызове входа задачи (в момент рандеву); 36
Рандеву как средство синхронизации и обмена данными task T 1 is entry E 1 (X : in Some_Type); end T 1; task T 2 is entry E 2; end T 2; task body T 1 is Var 1 : Some_Type; . . . begin. . . accept E 1 (X : in Some_Type) do Var 1 : = X; end E 2; . . . T 2. E 2; . . end T 1; task body T 2 is Var 2 : Some_Type; . . . begin. . ждет вызова ждет приема рандеву ждет приема ждет вызова рандеву T 1. E 1 (Var 2); . . accept E 2; . . . end T 1; 37
Асимметричное рандеву как модель поведения «клиентмастер» • Рандеву - вызывающая задача в точке вызова входа и вызываемая в точке приема вызова должны оказаться одновременно; • Вызывающая задача знает, вход какой именно задачи она вызывает (имя входа доступно только в префиксной форме, префикс - имя задачи, которой принадлежит вход), вызываемая - не знает, кто именно ее вызвал, лишь бы параметры были соответствующих типов - поэтому рандеву асимметричное; • Модель поведения «клиент-мастер» : у клиента есть часы, он хочет их починить и выбирает именно часовую мастерскую, часовому мастеру все равно, кто именно к нему пришел, лишь бы принес чинить часы, а не холодильник. • К одному и тому же мастеру могут выстраиваться очереди клиентов ожидающие рандеву очереди вызовов входов, выполнение оператора приема для данного входа отпускает из очереди первый вызов; • Пока задача ждет, чтобы ее вызов входа обслужили (или чтобы ее вход вызвали), она просто стоит на месте; 38
Взаимодействие асинхронных процессов • Описать отдельно взятый процесс относительно просто, основная сложность – во взаимодействии процессов: – совместное использование несколькими процессами одного и того же ресурса (разделяемые ресурсы); – взаимное исключение (в каждый момент времени ресурсом может пользоваться не более одного процесса); – «тупики» ; • Внешняя и внутренняя дисциплины использования разделяемых ресурсов: – кто и где следит за тем, чтобы разделяемый ресурс использовался корректно – сам ресурс или нечто (некто? ) вне его? 39
Взаимодействие асинхронных процессов: Адский подход • Процесс должен уметь выбирать варианты своего поведения в зависимости от своего состояния и готовности других процессов к взаимодействию с ним; • Средства управления взаимодействием процессов ориентированы на внутреннюю дисциплину использования разделяемых ресурсов как на более надежную: – разумно устроенный разделяемый ресурс допускает только корректное использование! • Каждый процесс проектируется в предположении, что мир, с которым он взаимодействует, устроен разумно, и все, что от него требуется – гарантировать разумность своего собственного поведения (процесс сам может для кого-то оказаться разделяемым ресурсом!); 40
Постановка задачи «взаимодействие через буфер» • Из внешней среды поступают однородные объекты (сообщения), с каждым из которых необходимо проделать два разных действия – анализ и синтез. Анализ и синтез выполняются независимо для разных объектов, для одного и того же объекта анализ следует за синтезом. При этом существенными являются временные характеристики: – минимальное время между поступлением сообщений – τ – максимальное время анализа – τ – ε, где ε << τ – максимальное время синтеза - 3 τ, среднее время синтеза τ – ε 1, где ε 1 << τ внешняя среда сообщение Анализ Синтез ответ внешняя среда 41
Решение - интерфейс • • Точка зрения пользователя (внешней среды) - надо иметь возможность по мере необходимости передавать сообщение, а по мере готовности - получать ответ Эти действия независимы и могут происходить асинхронно 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 Анализ_Синтез; 42
Решение - как им пользоваться? package Генератор_Сообщений is task Генератор is entry Start; end Генератор_Сообщений; with Анализ_Синтез; use Анализ_Синтез; package body Генератор_Сообщений is task body Генератор is Message : Сообщение; begin accept Start; package Потребитель_Сообщений is task Потребитель is entry Start; end Потребитель_Сообщений ; loop Message : = Сформировать_Сообщение (. . . ); Анализ. Принять (Message); end loop; end Генератор_Сообщений; with Генератор_Сообщений; with Потребитель_Сообщений ; . . . procedure Main is Ch : Character; begin Генератор_Сообщений. Генератор. Start; Потребитель_Сообщений. Потребитель. Start; . . . end Main; -- Мы не рассматриваем проблему -- завершения задач! with Анализ_Синтез; use Анализ_Синтез; package body Потребитель_Сообщений is task body Потребитель is Answer : Ответ; begin accept Start; loop Синтез. Выдать (Answer); Использовать_Ответ (Answer); end loop; end Потребитель_Сообщений; 43
Реализация взаимодействием через буфер Генератор_ Сообщений сообщение Анализ. Принять Синтез. Выдать ответ Потребитель_ Сообщений разбор интерфейс реализация Буфер 44
Реализация - общая структура -- Воспользуемся классической -- абстракцией буфера -- ограниченного размера with Любой_Буфер; package body Анализ_Синтез is type Разбор is new Сообщение; generic Размер : in Positive : = 10; type Элемент is private; package Любой_Буфер is procedure В_Буфер (X : in Элемент); procedure Из_Буфера (X : out Элемент); function Пуст return Boolean; function Полон return Boolean; end Любой_Буфер; task Буфер is entry Положить (X : in Разбор); entry Достать (X : out Разбор); end Буфер; task body Анализ is. . . ; task body Синтез is. . . ; task body Буфер is. . . ; end Анализ_Синтез; Осталось написать тела. . . 45
Реализация - тела задач Анализ и Синтез. . . в предположении, что Буфер - «умный» и позволяет себя использовать только корректно. . . task body Анализ is Моё_Сообщение : Сообщение; Готов : Разбор; begin loop accept Принять (X : in Сообщение) task body Синтез is Моё_Сообщение : Разбор; Готов : Ответ; begin loop Буфер. Достать (Моё_Сообщение); . . . -- Синтез ответа, -- do Моё_Сообщение : = X; end Принять; . . . -- анализ сообщения, -- формирование значения -- переменной Готов Буфер. Положить (Готов); end loop; end Анализ; формирование значения -- переменной Готов accept Выдать (X : out Ответ) do X : = Готов; end loop; end Синтез; 46
Реализация «умного» Буфера -- подготовка структуры task body Буфер is -- данных begin package Локальный_Буфер is new Любой_Буфер (Размер => 30; Элемент => Разбор); use Локальный_Буфер; 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; end loop; end Буфер; 47
Семантика оператора отбора • Вычисляются все охранные ограничения (порядок вычисления недетерминирован) и выбираются «открытые» альтернативы приема (охранное ограничение отсутствует или истинно); • Среди «открытых» альтернатив приема выбираются готовые к немедленному рандеву (очереди вызовов соответствующих входов не пусты); • Среди «открытых» и готовых к рандеву альтернатив приема недетерминированным образом выбирается одна и выполняется; • Если нет «открытых» и готовых к рандеву альтернатив приема, выполнение оператора зависит от его завершающей части – если таковой является альтернатива завершения, задача завершается, если она «больше никому не нужна» ; 48
Та же самая задача – на основе внешней дисциплины использования разделяемых ресурсов • Попробуйте решить тут же задачу, если единственным средством организации взаимодействия процессов является семафор… – при помощи семафора несложно обеспечить, чтобы процессы Анализ и Синтез использовали буфер в режиме взаимного исключения, но как обеспечить отсутствие тупиков (процесс Анализ захватил полностью заполненный буфер в исключительное использование)? – как обеспечить приоритет процесса Анализ при использовании буфера? 49
Разновидности оператора отбора - альтернатива задержки • Альтернатива задержки: если есть «открытые» альтернативы, но нет готовых к рандеву - ждем указанное время. Если за это время не появился подходящий вызов выполняем операторы альтернативы задержки; loop select accept Считать_Значение (T : in Temperature) do Текущая_Температура : = T; end Считать_Значение; • Если нам за 0. 1 секунды не сообщили новое значение температуры - бьем тревогу! -- анализируем новое -- значение температуры. . . or delay 0. 1; raise Сломался_Градусник; end select; end loop; 50
Разновидности оператора отбора - else часть. • ELSE-часть: если рандеву немедленно невозможно по любой причине - выполняем операторы после else; loop select accept Выдать_Значение (T : out Temperature) • «Драйвер градусника» постоянно пересчитываем текущую температуру и готовы выдать ее по первому требованию do T : = Текущая_Температура; end Выдать_Значение; else -- считаем значение для -- Текущая_Температура. . . end select; end loop; 51
Выбор варианта поведения задачей - клиентом • Оператор отбора есть оператор отбора вызова входа для обработки этого вызова, он используется в задачемастере. • Похожая конструкция может использоваться задачейклиентом при вызове входа; • В отличие от оператора отбора вызова входа, который может иметь несколько альтернатив приема, многоальтернативных конструкций для вызова входа нет; 52
Условный вызов входа • Если рандеву немедленно невозможно - так и не надо, займемся своими делами! loop select Card. Read (C); -- Вызов входа Read -- задачи Card Обработать_Карту (C); exit; else Локальные_Вычисления; end select; end loop; 53
Временн. Ой (Timed) вызов входа • Если рандеву немедленно невозможно - ждем не более явно оговоренного (в операторе задержки) времени. Если не дождались своей очереди отказываемся от вызова входа select Архив. Записать (X); or delay 5. 0; Put_Line (“К сожалению, архивная” & “система занята”); end select; 54
Асинхронная передача управления (по истечению интервала времени) • Асинхронная передача управления – это возможность прервать последовательность действий при наступлении некого события. Таким событием может быть вызов входа или наступление (истечение) некоторого момента (интервала) времени; -- предположим, мы не можем себе позволить -- тратить на некоторые действия слишком -- много времени select delay 5. 0; Put_Line (“Calculation is too long!”); then abort Horribly_Complicated_Recursive_Function (X, Y); end select; -- по истечении 5 секунд вычисление -- Horribly_Complicated_Recursive_Function -- будет прервано 55
Асинхронная передача управления (по наступлению события (вызову входа) • Командный интерпретатор с возможностью нажатия Ctrl-C; loop select Terminal. Wait_For_Interrupt; -- • Вызов входа Wait_For_Interrupt задачи Terminal (нажатие Ctrl-C) приводит к прерыванию обработки текущей команды Совмещенный с Ctrl-C -- вызов входа Put_Line (“Interrupted”); then abort Put_Line (“ ”); Get_Line (Command, Last); Process_Command (1. . Last)); end select; end loop; 56
Защищенные записи - зачем? • Наш буфер в решении задачи «Анализ-Синтез» хорош всем, кроме одного - он реализован задачей, то есть активным процессом со всеми накладными расходами и для программиста (надо заботиться, в частности, о запуске и завершении), и для реализации; • На самом деле буфер - разделяемый объект данных, для которого всего лишь требуются операции, обеспечивающие корректную и удобную работу с ним при условии использования несколькими асинхронными процессами; • Эту возможность обеспечивают защищенные записи (protected records): средства определения объектов данных – и одновременно дисциплины их использования; 57
Защищенные записи - что это такое? • • Защищенная запись объединяет данные, операции доступа к ним и особые правила выполнения этих операций; Как и обычная запись, защищенная запись имеет поля, но они скрыты от непосредственного доступа; Доступ к полям возможен лишь при помощи защищенных операций, объявленных в видимой части; Защищенные операции это: – функции; – процедуры; – входы; protected T is. . . -- объявления защищенных -- операций private. . . -- объявления полей. . . -- объявления скрытых -- защищенных операций end T; protected body T is. . . -- тела защищенных операций end T; 58
Простейший пример - разделяемая переменная • Требования к разделяемой переменной: – ее значение могут одновременно читать несколько процессов; – изменять значение переменной может лишь один процесс; – во время изменения значения должно быть невозможно считать это значение; -- Использование разделяемой переменной X : = Variable. Read; . . . Variable. Write(New_Value => Y); protected Variable is function Read return Item; procedure Write (New_Value: Item); private Data: Item; end Variable; protected body Variable is function Read return Item is begin return Data; end Read; procedure Write (New_Value: Item) is begin Data : = New_Value; end Write; end Variable; 59
Защищенные операции • Защищенные операции «принадлежат» защищенному объекту, при их вызове защищенный объект выступает в качестве неявного параметра вызова; • Защищенные функции могут лишь читать значения полей, защищенные процедуры и входы могут и читать и менять значения полей; • одновременно может выполняться несколько вызовов функций одного и того же защищенного объекта; • одновременно может выполняться не более одного вызова защищенной процедуры или входа (при этом не могут выполняться вызовы защищенных функций того же объекта); • с защищенным входом связаны очереди вызовов и барьерные ограничения 60
Выполнение защищенных операций • Защищенный объект (protected object - PO) может находится в одном из двух состояний: – «открыт» - готов к обработке вызова защищенной процедуры или входа, может обрабатывать вызовы защищенных функций; – «закрыт» - занят обработкой вызова защищенной процедуры или входа, при этом вызовы защищенных операций не могут «проникнуть» в PO и «неорганизованно» (нет очередей!) «толпятся» снаружи; • Вызов защищенной процедуры или входа «захватывает» РО. Выполнение защищенной процедуры начинается немедленно. Для защищенного входа проверяется барьерное ограничение. Если оно истинно - вызов входа выполняется. Иначе вызов ставится в очередь к входу; 61
Выполнение защищенных операций • Самое интересное происходит после завершение выполнения защищенной процедуры или входа, и после того, как в очередь добавлен новый вызов (PO все еще «закрыт» !): – перевычисляются барьерные ограничения для всех входов (ведь только что выполнившаяся процедура или вход могли изменить ситуацию, а длина очереди – часть состояния объекта!) – если обнаруживаются входы с истинными значениями барьеров и непустыми очередями входов) - недетерминированным образом выбирается один вход из очереди и выполняется; – и все снова - перевычисление барьеров, проверка очередей, пока не окажется, что нет ни одного входа с истинным барьером и непустой очередью. Лишь тогда PO, наконец, «открывается» ; • Барьерные ограничения не могут зависеть от (фактических) параметров входов! 62
«Умный» буфер protected type Bounded_Buffer is entry Put (X: in Item); entry Get (X: out Item); private A : Item_Array (1. . Max); I, J : Integer range 1. . Max : = 1; Count : Integer range 0. . Max : = 0; end Bounded_Buffer; -- Использование буфера: -- * возможно только в режиме -- взаимного исключения; -- protected body Bounded_Buffer is entry Put (X : in Item) when Count < Max is begin A (I) : = X; I : = I mod Max + 1; Count : = Count + 1; end Put; entry Get (X : out Item) when Count > 0 is begin X : = A(J); J : = J mod Max + 1; Count : = Count - 1; end Get; * тупики исключены; My_Buffer : Bounded_Buffer; . . . end Bounded_Buffer; My_Buffer. Put (Something); . . . My_Buffer. Get (To_Something); 63
«Многозначный» семафор • Семафоры - это обычно «системные» (т. е. внеязыковые) объекты. Однако семафор легко реализуется как PO; • В данном PO присутствуют все три типа защищенных операций; • PO могут иметь дискриминанты; protected type protected body Counting_Semaphore is entry Secure when Current_Count > 0 is begin Current_Count : = Current_Count - 1; end Secure; Counting_Semaphore (Start_Count: Integer : = 1) procedure Release is begin is Current_Count : = Current_Count + 1; entry Secure; end Release; procedure Release; function Count return Integer; private Current_Count: Integer : = Start_Count; end Counting_Semaphore; function Count return Integer is begin return Current_Count; end Counting_Semaphore; 64
Сигналы • Как и семафоры, обычно реализуются «системными» переменными, но в Аде легко реализуются как PO; • Реализация “классического” сигнала; • Почему Wait - вход, а Signal процедура? protected Сигнал is entry Ждать; protected body Сигнал is entry Ждать when Есть_Сигнал is begin Есть_Сигнал : = False; -- сигнал получен end Ждать; procedure Послать is begin -- ждать появления сигнала Есть_Сигнал : = True; procedure Послать; -- устанавливаем барьер -- послать сигнал -- для Ждать в True private end Послать; Есть_Сигнал: Boolean : = False; end Event; end Сигнал; 65
Сигнал «Слушайте все!» • • Другая разновидность сигнала его получают сразу все ожидающие, но если сигнала никто не ждет - сигнал пропадает; Пример перенаправления вызова входа в другую очередь; protected body Сигнал is entry Ждать when Есть_Сигнал is begin null; -- тело «пустое» ! end Ждать; entry Послать when True is -- барьер всегда истинный! begin if Ждать'Count > 0 then Есть_Сигнал : = True; protected Сигнал is requeue Обновить; entry Ждать; entry Послать; end if; end Послать; private entry Обновить; -- приватный вход! Есть_Сигнал : Boolean : = False; end Сигнал; entry Обновить when Ждать'count = 0 is begin Есть_Сигнал : = False; end Обновить; end Сигнал; 66
То же самое - но намного проще! • • PO может не содержать данных, а его операции могут иметь пустой код, но даже такой PO может оказаться полезным! protected Сигнал is Реализуемая этим PO функциональность полностью эквивалентна предыдущему примеру (с булевским флагом и requrue); protected body Сигнал is entry Ждать; entry Послать; end Сигнал; entry Ждать when Послать'Count > 0 is begin null; end Ждать; entry Послать when Ждать'Count = 0 is begin null; end Послать; end Сигнал; 67
Что еще можно рассказать об асинхронных процессах в Аде? • Задачные и защищенные типы: задачи и защищенные записи как объекты данных и элементы структур данных; • Динамическое создание задач и защищенных объектов; • Управление приоритетами; • Исключения, возникающие в ходе рандеву; • Подходы к разработке многопроцессных программ; • Ограничения, повышающие предсказуемость поведения систем с асинхронными процессами; • … 68
Система программирования GNAT (www. adacore. com) • Включает в себя: – – компиляторы С, С++; – развитый инструментарий (метрики, статический анализ размера стека, средства обнаружения утечек памяти, статический контролер кода, …); – • компилятор Ады, соответствующий последней редакции стандарта (Ada Reference Manual, ISO/IEC 8652: 2007(E) Ed. 3 ), являющийся частью многоязыковой среды gcc; AWS, XMLAda, GTKAda, . . . среду разработки GPS; традиционный набор средств разработки (отладчик, средства навигации, возможности форматирования на лету, …); Существует в виде: – – – индустриальной версии; версии для университетов; свободно доступной версии для разработки GPL-программ; • Все исходные тексты доступны, основной язык реализации – Ада. • Интерфейс всех компонент системы программирования GNAT одинаков на всех платформах, где она реализована. 69
Система программирования GNAT – индустриальная версия • Распространяется путем продажи контрактов на техническую поддержку (24 x 7 x 365). Техподдержка включает: – развитие технологии по запросам пользователей; – консультации по языку и по системе программирования GNAT; – содержательная реакция о сообщении об обнаруженной проблеме в течение одного рабочего дня; – предоставление версий технологии с устраненными дефектами; • Реализована на всех индустриальных платформах; • Кросс-компиляторы для Lynx. OS, Vx. Works, Vx. SIM, поддержка Bare Boards, high integrity версии. 70
GNAT Academic Program (GAP) • Распространяется бесплатно среди учебных заведений, для получения достаточно прислать по факсу заполненную анкету (1 страница); • Доступна в среде MS Windows, Linux, Sparc-Solaris, по функциональности полностью идентична индустриальной версии; • Обмен опытом и учебными материалами с другими участниками GAP-программы; • Поддержка пользователей (без предоставления версий с исправленными ошибками); 71
GNAT GPL • Можно бесплатно взять на https: //libre. adacore. com/; • Полностью под GPL, позволяет разрабатывать только GPLпрограммы; • Поддержка разработчиков отсутствует; 72
Где и что почитать про Аду? • http: //www. ada-ru. org – русскоязычный сайт, созданный нашими Ада-энтузиастами – среди прочего, содержит: – книгу по Аде-95 – достаточно полный перечень ссылок на англоязычные Ада-ресурсы • Обзор и обоснование проектных решений для версии стандарта 1995 года (Ada 95 Rationale) http: //www. adaic. com/standards/ada 95. html 73
Заключение • Ада является существенным компонентом мировой программной индустрии • Не использовать Аду просто потому, что о ней не известно специалистам по информационным технологиям, едва ли разумно • Отечественные специалисты по ИТ должны иметь достаточно информации о современном состоянии Ада технологий, чтобы принимать осознанные решения относительно их использования или неиспользования в тех или иных проектах 74
614ea4119d92eaba1cabe665ee8fd56b.ppt