Книга
Книга
Предисловие редактора перевода
Системные аналитики находятся сегодня примерно в таком положении, которое можно коротко охарактеризовать тремя словами: «сапожник без сапог». Они создают сложные автоматизированные системы управления, насыщенные десятками ЭВМ, а средств автоматизации собственного труда практически не имеют. Вся их деятельность напоминает при этом бег на длинную дистанцию с барьерами. Определяя требования к системе, они с большими трудностями преодолевают языковой барьер в общении с «заказчиком», который хорошо знает существо интересующих разработчиков проблем, но умеет говорить о них только «своими словами». Создав, наконец, то, что должно называться системой, системные аналитики встречают на своем пути психологический барьер, мешающий пользователям быстро освоить совершенно незнакомые и непривычные для них средства автоматизации, идущие на смену привычному карандашу и бумаге. Когда же новая система «внедрена» и начинает конкурентную борьбу со старой, ее разработчиков подстерегает еще и «иммунологический» барьер, так как продукт их деятельности оказывается инородным телом для давно сформировавшегося консервативного организационного механизма.
В практике создания АСУ известно много случаев неудачной реализации и даже полного крушения довольно крупных проектов, не сумевших преодолеть тот или иной из указанных барьеров. Спросите у любого системного аналитика, в чем основная причина подобных неудач, и он наверняка ответит, что дело в отсутствии удобного языка представления проектных решений и замыслов, позволяющего как можно раньше привлекать будущих пользователей системы к ее разработке. Этот язык проектирования, с одной стороны, должен делать идеи системных аналитиков понятными заказчику создаваемой системы, а с другой — предоставлять системным аналитикам средства достаточно формализованного и однозначного определения проектных решений, подлежащих реализации в виде совокупности конкретных пакетов прикладных программ, образующих Целостную систему программного обеспечения.
Поиски в этом направлении породили целый ряд новых принципов разработки крупномасштабных систем: нисходящее проектирование, функциональная декомпозиция, структурное программирование, модульное конструирование, сквозной структурный контроль и др. Новые принципы позволили организовывать согласованное параллельное проектирование отдельных частей больших программных комплексов, в результате чего важной специальной проблемой стало обеспечение приемлемого уровня их надежности и полной совместимости. Возникшие при этом дополнительные требования к вновь создаваемым языкам высокого уровня стали фактически затрагивать системные аспекты процесса проектирования программных средств: распараллеливание процессов, обработку данных в реальном масшта- бе времени, гибкое управление представлением данных, раздельное компилирование программных модулей, эффективное использование вычислительных ресурсов и т. п. Особенно важную роль эти системные аспекты приобретают с расширением масштабов применения микропроцессорной техники и созданием распределенных управляющих систем.
Предлагаемая вниманию читателей книга является по существу первой крупной работой, в которой отмеченные выше системные проблемы рассматриваются применительно к самым ранним этапам проектирования — от разработки концептуальных представлений и основных принципов построения будущей системы до определения способов ее программной реализации средствами языка Ада.
Следует заметить, что эта книга не о языке Ада и не о программировании вычислительных машин, а об оригинальной методологии логического проектирования сложных программнотехнических комплексов, которая прошла практическую проверку при создании систем обработки сигналов, вычислительных сетей, систем автоматизации учрежденческой деятельности и автоматизированных систем управления технологическими процессами.
Цели, задачи и содержание книги очень подробно изложены в авторском предисловии, дающем читателю возможность получить вполне объективное представление о существе рассматриваемых в книге проблем и предлагаемых методов их решения. Монография носит многоплановый характер, однако ее стержневая идея состоит в том, чтобы вооружить разработчиков, не имеющих большого практического опыта создания систем, необходимыми инструментальными и изобразительными средствами, которые могут обеспечить коллективу, работающему над единым проектом, должный уровень качества разработок.
В книге содержится очень большое число иллюстраций, дополняющих, а не повторяющих текстовой материал и несущих
самостоятельную смысловую нагрузку. Для лучшего понимания излагаемых концепций и методов этим иллюстрациям при чтении должно быть уделено не меньшее внимание, чем основному тексту, поскольку с помощью графических средств автор проводит последовательную детализацию предлагаемой методологии логического проектирования программно-технических комплексов.
Следуя стремлению автора к максимально доходчивому изложению далеко не элементарных идей, мы снабдили используемые операторы языка Ада, типы данных, имена пакетов, процедур, задач и других объектов русским переводом в тексте или в перечнях условных обозначений. На рисунках же все указанные элементы сознательно оставлены на языке оригинала, чтобы подчеркнуть основное достоинство предлагаемой методологии проектирования — возможность прямого преобразования графических представлений в Ада-программы. Что касается специальной терминологии, то здесь мы старались по возможности не отклоняться от уже выходивших на русском языке изданий, если того не требовала авторская интерпретация терминов, «привязанная» к конкретным аналогиям из области организационных систем.
Для чтения этой книги совсем не обязательно быть программистом: достаточно лишь иметь некоторое представление о принципах использования средств вычислительной техники и систем передачи данных в человеко-машинных комплексах. Книга может служить хорошим учебным пособием для студентов, специализирующихся в системном программировании и разработке автоматизированных систем управления различного назначения. Для них особенно важно выполнение по каждой главе помещенных в тексте и в конце книги заданий, часть из которых может быть положена в основу тем курсовых проектов.
С большим интересом должны встретить эту книгу системные аналитики и специалисты, занимающиеся созданием систем автоматизированного проектирования. Разумеется, для эффективного применения изложенных в книге идей необходимо иметь подходящий транслятор с языка Ада в составе программных средств серийных ЭВМ. Однако здесь уже слово за «индустрией программного обеспечения», которая пока явно отстает от требований дня.
Е. К. Масловский
Предисловие
'Автор книги преследует несколько целей:
Дать широкой читательской аудитории построенное по нис* ходящему принципу вводное описание средств языка Ада, ори* ентированных на проектирование систем.
Показать и проиллюстрировать конкретными примерами по* лезную в практическом смысле графическую символику проек* тов, выполняемых средствами языка Ада, с тем чтобы она могла использоваться на различных уровнях системного проекта* рования:
для концептуального представления принципов организа* ции систем;
как средство взаимного общения разработчиков в процес* се неформального представления проектных решений и выбора подходов к проектированию;
как возможную основу средств автоматизированного про* ектирования систем, для описания и реализации которых применяется язык Ада.
Вооружить разработчиков систем, не обладающих большим практическим опытом, определенным «мировоззрением» в этой области, конкретными стратегическими принципами, тактически* ми приемами и методами эффективного выполнения процесса проектирования в рамках концепции жизненного цикла.
Эта книга должна оказаться особенно полезной тем относи* тельно неопытным разработчикам, которые уже сталкиваются или столкнутся в скором времени с проблемой создания систем на основе микропроцессоров. Она даст им в руки необходимые инструментальные средства, методы и представления, которые способны обеспечить коллективу, работающему над общим про* ектом, должный уровень качества разработок. Последние до* стижения в области микропроцессорной техники и технологии, имеющие взрывной характер, привели к резкому удешевлению изделий микроэлектроники и вызвали острую нехватку опытных специалистов, умеющих конструировать микропроцессорные си* стемы и обладающих необходимыми для этого навыками. Си* туация складывается таким образом, что ответственность за создание подобных систем ложится на плечи неопытных инже*
неров-электриков и специалистов по вычислительной технике, а они не имеют надлежащей профессиональной подготовки или достаточных знаний для того, чтобы сразу принимать правильные решения. Участниками проектов систем становятся специалисты в совсем иных областях, хотя и имеющие большой практический опыт работы. Эта книга призвана помочь им в новой сфере деятельности.
Большая часть книги доступна каждому, кто хотя бы немного знаком с вычислительными машинами и умеет программировать на таких языках, как Паскаль, ПЛ/М или Си. При этом знакомство с вычислительной техникой предполагает не столько использование ЭВМ как средства реализации прикладных программ, написанных на языках высокого уровня, сколько умение применять ЭВМ в качестве структурных компонентов создаваемых систем.
Книга доступна студентам второго и третьего года обучения, специализирующимся в области вычислительной техники и конструирования вычислительных систем, а также большинству студентов третьего и четвертого курсов электротехнических специальностей с факультативным преподаванием основ вычислительной техники или специализирующихся в области обработки данных.
Аспиранты и все те, для кого разработка систем является частью их профессиональной деятельности, тоже найдут эту книгу полезной для себя, так как она поможет им приобрести недостающие знания в результате освоения развитых в книге единых в концептуальном плане подходов к решению задач, с которыми этой группе читателей уже приходилось сталкиваться на практике. Особый интерес для них должны представить помещенные в конце книги практические примеры применения излагаемых методов проектирования систем.
Можно сказать, что эта книга нацелена на будущее усовершенствование методологии создания систем, так как в ней используется новый язык программирования Ада, предоставляющий широкий набор абстрактных конструкций и инструментальных средств для описания модульных систем. Книга знакомит читателя и с самим языком Ада, однако излагаемый в ней материал отнюдь не требует детальных знаний этого языка, которые легче будет приобрести уже после прочтения этой книги. Такой подход к изучению языка Ада может оказаться даже более эффективным, поскольку в данном случае формированию навыков программирования будет предшествовать развитие необходимых концептуальных представлений. Язык Ада рассматривается по большей части как некоторая версия Паскаля, дополненная базовыми концепциями пакетов и задач, а новые понятия, присущие именно языку Ада, вводятся всюду посте-
пенно и сопровождаются необходимыми пояснениями. Благодаря этому при чтении книги нет необходимости обращаться к какой-либо другой литературе. Программы на языке Ада могут использоваться просто в качестве спецификаций целевых систем, не обязательно реализуемых в среде Ада-программ, и поэтому излагаемые в книге методы никак не связаны с использованием языка Ада как средства реализации систем. Разумеется, в мире программного обеспечения этот язык в конечном итоге может Оказаться доминирующим благодаря той ключевой роли, которая отводится ему в настоящее время министерством обороны США. Кроме того, существует по крайней мере одна фирма — Изготовитель микропроцессоров, которая обеспечивает аппаратную поддержку языка Ада на уровне кристаллов. Однако целесообразность использования его в качестве языка проектироваНия систем определяется отнюдь не «модой», а тем фактом, что в языке Ада имеются мощные выразительные средства, позволяющие описывать модульные системы с параллельными процессами в терминах, точно соответствующих процедурам конструирования систем.
Богатые выразительные средства языка Ада при неумелом их использовании таят в себе для непосвященных разработчиков множество «подводных камней», в связи с чем использова- ййе языка Ада в книге сознательно ограничено. Это сделано, во-первых, с целью обеспечения доступности материала книги широкому кругу читателей и, во-вторых, с намерением вооружить их такими принципами проектирования систем, которые позволили бы избежать большинства скрытых опасностей, свойственных языку Ада. Автор постоянно стремится к максимальному упрощению изложения рассматриваемых в книге концепций в соответствии с известным «кисс-принципом»1).
Подход к процессу проектирования, развиваемый автором, был подсказан работами Э. Иодана, Л. Константина и Дж. Майерса в области структурного проектирования.
Что же касается графической символики для систем, проектируемых средствами языка Ада, то она возникла естественным образом как результат попыток применения и доходчивого объяснения понятий этого языка. В таких случаях всегда оказывалось, что обсуждение удобнее всего было проводить на основе рисунков, изображаемых на доске или бумаге. Детали предложенной символики разработаны автором этой книги, но основной принцип условных обозначений подсказан в какой-то мере нотацией, которая используется фирмой Intel для описа-
') Термин «кисс-принцип» (KISS-principle) представляет собой аббревиатуру английских слов Keep It Simple Stupid (Делай проще, глупец!), — Прим* ред*
ния принципов работы микропроцессора iAPX432 с языком Ада, а также символикой, применяемой Г. Бушем при толковании понятий этого языка. Идея использования графической системы обозначений возникла благодаря успешному применению и развитию структурных графов Хансена в параллельном Паскале, которому посвящена более ранняя книга автора, написанная с Б. Боуденом.
Графическая система обозначений обеспечивает конкретное однозначное эскизное отображение необходимых свойств разрабатываемых Ада-программ. Такие эскизы являются удобным инструментом сжатого «стенографического» описания как программ, так и систем, проектируемых средствами языка Ада.
Автор придерживается твердого убеждения, что обсуждение идей структурного проектирования в отсутствие прямой связи между графическими представлениями системных проектных решений и конкретными способами их программной реализации с использованием языка высокого уровня может привести к путанице и неправильной интерпретации описаний, если работа над проектом не координируется на каждом шаге опытным специалистом в области структурного проектирования. Поскольку основная цель книги состоит в том, чтобы дать читателю относительно самостоятельное (замкнутое) введение в проблему проектирования систем, она, естественно, должна носить характер учебного пособия, исключающего необходимость обращения за разъяснениями к опытным специалистам. Автор надеется, что ему удалось достичь поставленной цели благодаря использованию специальной графической нотации, которая позволяет вести обсуждение вопросов структурного проектирования на довольно высоком уровне и в то же время не заставлять читателя отрываться от обычных для него представлений.
Эта книга призвана помочь читателям в развитии концептуального мышления относительно проектируемых систем на логическом уровне. Технические специалисты, как правило, интуитивно хорошо представляют принципы модульности и параллельности, для которых, однако, нет адекватных средств отображения в широко распространенных языках программирования. Для подкрепления интуиции необходимы те или иные способы наглядного представления систем, состоящих из взаимодействующих модулей, языковые средства которых обеспечивали бы непосредственную реализацию таких представлений в языковых конструкциях, а также ряд примеров системного проектирования, иллюстрирующих применяемые методы компоновки новых систем из «набора деталей». Именно эти цели и преследует автор данной книги.
Традиционно сложная проблема организации параллельных процессов рассматривается в книге на примерах, относящихся
к области повседневного взаимодействия людей, что облегчает понимание развиваемых концепций. При этом читателю предлагается аналогами задач считать отдельных индивидуумов, а аналогами взаимодействий между задачами посредством предусмотренного в языке Ада механизма рандеву — взаимодействия между людьми в деловых учреждениях. Благодаря такому подходу проблемы параллельности процессов и способы их решения приобретают для читателя знакомые очертания и уже не кажутся ему чем-то совершенно новым и невообразимым.
Излагаемый в книге материал охватывает как вопросы конструирования систем технического назначения, так и сам процесс проектирования; основные проблемы и принципы, касающиеся тех и других аспектов, рассматриваются не на абстрактном уровне, а в контексте конкретных примеров.
Приводимые примеры служат своего рода плацдармом для штурма проблем общего характера в рамках практического опыта автора, охватывающего автоматизированные системы управления технологическими процессами, взаимодействие ЭВМ, автоматизацию учрежденческой деятельности и системы обработки сигналов. При этом представления, получаемые из рассматриваемых примеров, могут легко распространяться на новые проблемные области.
В книге рассматриваются вопросы проектирования систем, реализуемых в Виде совокупности аппаратных и программных средств. Следовательно, она касается не столько программирования, сколько структуры создаваемых систем. Абстрактные понятия, используемые на верхнем уровне процесса проектирования, вводятся постепенно, «сверху—вниз», что позволяет планомерно развивать интуитивные представления читателя о них без привлечения сложных синтаксических языковых конструкций, в которых легко утратить понимание физической природы предметов и явлений. Многочисленные примеры программных реализаций, даваемые применительно ко всем ключевым абстрактным объектам, помогают читателю постоянно ощущать твердую почву под ногами, имея дело с абстрактными представлениями. Однако эти примеры рассматриваются лишь после того, как вводятся соответствующие абстракции. Ряд примеров иллюстрирует проектирование реальных систем почти независимо от их программирования.
Поскольку проектирование систем всегда ведется не на уровне их физической реализации, а на более высоком, логическом уровне, этот процесс не должен быть связан с рассмотрением деталей. В соответствии с этим требованием приводимые в книге примеры использования средств языка Ада редко представляют собой законченные программы, в которых все расставлено по своим местам. Они скорее напоминают скелет-
ные схемы будущих программ в символической нотации, а именно это и есть логический уровень проектирования систем.
Примеры проектов рассматриваются в книге поэтапно, что хорошо воспроизводит обстановку «сквозного структурного контроля» проектных решений1). На рисунках структура проектируемых систем отображается в таком виде, в каком ее мог бы представить графически специалист, проводящий рабочее совещание по сквозному структурному контролю. Далее эта структура воплощается в скелетные схемы Ада-программ, соответствующие требованиям к материалам, передаваемым на рассмотрение первой сессии сквозного структурного контроля программных средств. Цель здесь состоит в том, чтобы показать, как можно провести разработку и обсуждение проектных решений с привлечением изобразительных средств, расширяющих возможности взаимного общения участников проекта.
Многие примеры и проблемы взяты автором из собственного опыта и практической работы его коллег над проектами, представлявшими определенные трудности для реализации. Это еще одна причина, по которой изложение материала носит неформальный характер: реальные проекты невозможно описать подробно в книге весьма ограниченного объема, но сконцентрированный в них опыт заслуживает тщательного изучения.
Изложенные в книге идеи прошли проверку в учебной аудитории в рамках нескольких курсов лекций для студентов старших курсов и аспирантов факультета системотехники и вычислительной техники Карлтонского университета, а также слушателей краткосрочных курсов университетской ассоциации и промышленных кругов. В ходе этой преподавательской работы, начавшейся в 1980 г., идеи автора претерпевали изменения, обновлялись и совершенствовались.
Книга состоит из трех частей. Части I и II являются вводными и должны быть доступны для читателей с минимальной начальной подготовкой. Первая из них содержит введение в предмет, обоснование актуальности рассматриваемых вопросов и обзор языка Ада как средства проектирования систем. Во второй части дается введение в логическое проектирование с использованием языка Ада, излагаются методы наглядного описания систем и иллюстрируется их применение на многочисленных простых примерах. В части III принципы логического проектирования рассматриваются более подробно. Сначала
’) Сквозной структурный контроль представляет собой организационный механизм объективного первичного анализа документации проектов и текстов программ специалистами, равными по положению, не предусматривающий никаких мер административного воздействия. Концепции сквозного структурного контроля достаточно подробно изложены в книге: Дж. Хьюз, Дж. Мичтом, Структурный подход к программированию, М.; Мир, 1980. — Прим. ред.
проводится достаточно детальный анализ некоторых свойств языка Ада, которые влияют на организацию процесса проектирования. Затем рассматриваются вопросы модульности, надежности, структуры проектируемых систем на примере разработки подсистемы передачи данных, реализующей простой протокол информационного обмена. В заключение обсуждаются общие проблемы конструирования модульных систем с параллельными процессами и в качестве примера приводится проект, предназначенный для реализации протокола Х.25 в системе с коммутацией пакетов.
В связи с выходом этой книги я считаю своим долгом выразить признательность прежде всего Элен Карлайл: если бы не ее проворные пальцы, летавшие над клавишами текстового процессора, книге не суждено было появиться на свет.
Особой благодарности заслуживает Стив Митчелл, внесший свой вклад в подбор и обсуждение идей и примеров, содержащихся во всех частях книги, но особенно в гл. 7, а также Элис Синьор, оказавший неоценимую помощь автору своими критическими замечаниями при просмотре окончательного варианта рукописи.
Я хотел бы, кроме того, поблагодарить всех моих студентов, которые терпеливо «испытывали» на себе все многочисленные усовершенствования читавшегося курса лекций.
Ряд идей, изложенных в этой книге, явился побочным результатом научно-исследовательских работ по контрактам с федеральными министерствами связи и национальной обороны, а также работ, субсидировавшихся Национальным Советом по научно-техническим исследованиям. Автор искренне благодарен этим организациям за их финансовую поддержку.
Я никогда не сумел бы начать работу над этой книгой без настойчивых советов моего коллеги Арчи Боуэна.
Формированию излагаемых в книге концепций проектирования и реализации систем на протяжении многих лет способствовали обсуждения идей с моими коллегами и студентами, число которых столь велико, что всех их назвать невозможно, но особой признательности заслуживает в этой связи Деннис Мак-Киннон.
Наконец, я хотел бы поблагодарить всех членов моей семьи за то, что они так долго мирились с присутствием Ады в нашем доме.
Р. Дж. Бар
Часть I
Концептуальные основы системного проектирования
В этой части книги дан постепенно детализируемый обзор языка Ада как средства проектирования систем. Подготовленный читатель (знакомый с языком Ада) может пропустить эту часть и перейти непосредственно к части II.
Глава 1
Введение в проблему
Обоснование предлагаемого подхода
В книге описывается подход к проектированию систем с использованием средств языка Ада — подход, который можно охарактеризовать как метод объектно-ориентированного структурного проектирования.
Этот метод предоставляет в распоряжение разработчика средства для описания и проектирования систем в среде языка Ада с использованием концепции черного ящика и рисунков типа эскизов; такие рисунки понятны каждому и способствуют интуитивному пониманию физической сущности системы. Основным побудительным мотивом к разработке предлагаемого метода послужило твердое убеждение, что улучшение взаимопонимания между создателями систем и расширение возможностей отображения их интуитивных представлений должны привести в конечном счете к повышению качества конкретных проектов. Нам представляется правомерным утверждение, что одна доходчивая картинка говорит гораздо больше, чем тысячи строк какой-либо программы.
Термин объект в данной книге относится к системной компоненте с характеристиками черного ящика. Другими словами, внутренняя организация этой компоненты неизвестна пользователю, который видит лишь спецификацию ее интерфейса. В соответствии с таким использованием термина объектами в языке Ада являются пакеты, задачи и процедуры. Понятия объектов
в языке Ада и механизмов их взаимодействия представляют собой некие образы, позволяющие описывать систему как набор черных ящиков, закоммутированных кабелем, т. е. в виде аппаратных средств. Такое образное представление полезно и для удобства общения и для выбора интуитивных представлений.■
Данная глава посвящена главным образом обоснованию предлагаемого подхода и уточнению его роли в проектировании систем. В разд. 1.2 процесс проектирования рассматривается с позиций концепций жизненного цикла системы. Современные проблемы и перспективные направления развития методов проектирования и реализации систем, порожденные успехами технологии («технологическим взрывом») и кризисом программного Цбеспечения, исследуются в разд. 1.3, а в разд. 1.4 резюмируются основные особенности предлагаемого подхода. Нетерпеливый читатель может без потери связности изложения пропустить разделы 1.2 и 1.3.
Проектирование системы и ее жизненный цикл
В данной книге рассматриваются две стороны проектирования, связанные с получением ответа на вопрос как, а именно: 1) непосредственно процесс проектирования, т. е. методология создания проекта системы,
2) технические аспекты системного проектирования, иначе говоря, факторы, влияющие на структуру создаваемой системы.
В контексте жизненного цикла системы проектирование является составной частью процесса разработки и развития системы в целом. Очень укрупненно фазы жизненного цикла системы можно представить следующим образом.
АНАЛИЗ
В этой фазе анализируются конкретные практические потребности с целью определения возможности их удовлетворения.
ОПИСАНИЕ
Эта фаза связана с выработкой внешних технических требований к системе.
ПРОЕКТИРОВАНИЕ
Фаза, в которой разрабатывается проект всей системы в целом, включающий
— интерфейс пользователя,
— описание функций системы,
— архитектурные принципы построения системы,
— план испытаний, основанный на сформулированных технических требованиях к системе и общем ее проекте. у
РЕАЛИЗАЦИЯ
. Фаза реализации системы состоит из этапов
конструирования отдельных модулей,
испытаний и отладки готовых модулей,
объединения модулей в подсистемы для окончательной компоновки системы.
ПОСТАВКА
В этой фазе осуществляется передача системы заказчику с проведением — аттестации системы на основе плана испытаний, -— приемо-сдаточных испытаний с участием заказчика.
ЭКСПЛУАТАЦИЯ И СОПРОВОЖДЕНИЕ
Эта фаза охватывает процедуры внесения необходимых изменений для исправления ошибок и удовлетворения изменяющихся потребностей.
Концепция жизненного цикла целостной системы рекурсивно связана с жизненными циклами, порождающими ее аппаратную и программную части.
В данной книге рассматривается в основном разработка логической структуры системы как часть фазы системного проектирования. Остальные фазы жизненного цикла в явном виде не детализируются, однако на протяжении всей книги постоянно подчеркивается их влияние на процесс проектирования.
В книге показывается, что процесс проектирования представляет собой совокупность неформальных процедур, поскольку невозможно, следуя некому рецепту, повернуть ту или иную ручку и получить готовый проект системы. Поэтому автор, отказавшись от попытки создания какой-либо формализованной методологии, сосредоточил внимание на изложении неформальных принципов реализации отдельных этапов системного проектирования, которые иллюстрируются многочисленными примерами.
В процессе проектирования логической структуры системы приходится иметь дело с целым рядом факторов технического характера, с тем чтобы обеспечить аккуратную разработку безошибочного проекта, удовлетворяющего всем системным требованиям. Эти факторы могут быть как качественными, так и количественными. Качественные аспекты проектирования включают модульность, гибкость и надежность системы. Количественные факторы связаны с описанием принципов функционирования системы сточки зрения обеспечиваемого времени реакции и производительности. Факторы, влияющие на надежность системы, рассматриваются как качественные. После введения такой классификации можно сказать, что особое значение в этой книге придается качественным техническим факторам проектирования
систем. Особенность изложения материала заключается в разборе действия указанных факторов на конкретных примерах.
Некоторые замечания об аппаратных и программных средствах
Исторически сложилось так, что две составные части любой системы—аппаратные и программные средства — имеют совершенно различные характеристики и всегда разрабатывались совсем непохожими методами. Наблюдаемый технологический взрыв в корне изменяет это положение дел. Внутренне присущая аппаратным средствам модульность навела специалистов по системам на мысль о новом подходе к созданию программных средств, которые в свою очередь позволяют проектировать и описывать и программы, и аппаратные средства с использованием программных методов. В этом смысле аппаратные и программные средства все более сближаются.
В определенных сферах применения современные методы разработки программного обеспечения обещают «подорвать авторитет» исторически сложившейся концепции жизненного цикла. Более того, появление вездесущих персональных ЭВМ делает процесс разработки средств программного обеспечения доступным практически каждому.
Цель этого раздела состоит в том, чтобы установить степень соответствия материала данной книги наблюдаемым тенденциям.
Аппаратные средства как источник идей для программных средств
Представьте себе на мгновение счастливчика, разрабатывающего технические средства. Создаваемые им компоненты обладают изначально присущей им физической реальностью. Их можно с помощью кабелей и разъемов соединить в группы, подсистемы или системы с четко определенными характеристиками сопряжений (интерфейсов), что иллюстрирует рис. 1.1. Любой модуль, подсоединенный к другому с помощью кабеля и разъема, можно без ущерба для системы в целом отсоединить и заменить совместимым по разъему модулем с совершенно отличной внутренней структурой. Поскольку совместимость на уровне разъемов обеспечивает рост объемов производства компонентов систем, становится возможным принятие альтернативных решений о покупке отдельных модулей или изготовлении их собственными силами. Наконец, при исчезновении питания или блокировании функции, выполняемой конкретным модулем, в случае
Iпо разъему [I1Iпо разъему [I1Рис. 1.1. Концептуальная модель ситемы в аппаратном представлении.
Iпо разъему [
I1
Iпо разъему [
I1
аппаратных средств оказывается возможной их реконфигурация в процессе эксплуатации.
Другая отличительная особенность аппаратных средств Типа тех, которые изображены на рис. 1.1,— это возможность параллельного функционирования двух и более модулей системы, причем любой модуль может сам состоять из параллельно работающих частей.
Концепции совместимости на уровне разъемов и параллелизма настолько естественны в мире технических средств, что уже совершенно не допускают какого-либо иного образа мышления в этом плане. Однако в области программного обеспечения исторически ситуация сложилась по-другому. Получившие широкое распространение традиционные языки программирования не содержат ни средств обеспечения совместимости модулей, ни средств реализации параллелизма. До недавнего времени немногие языки, которые действительно обладали такими возможностями, либо не имели широкого распространения, либо не были доступны широкому кругу пользователей. Различные организации, осознавшие необходимость подобных функций, пытались нестандартными способами так расширить стандартные языки, чтобы они удовлетворяли указанным требованиям. В итоге широкое распространение получили нестандартные узкоспециализированные методы разработки программного обеспечения.
В языке Ада, однако, идеи совместимости и параллелизма проводятся повсеместно и последовательно. В нем имеются средства для работы как с последовательными модулями (пакетами), так и с параллельными (задачами и содержащими их активными пакетами). Как пакеты, так и задачи снабжаются своего рода аналогами разъемов, причем каждому разъему
соответствует отдельное описание. Изящная унифицированность средств языка Ада является следствием того факта, что при внешнем рассмотрении гнезда пакетов и задач очень схожи между собой. Благодаря этому облегчается описание системы, состоящей из взаимосвязанных модулей различных типов.
Программа, написанная на языке Ада, почти в той же мере доступна для реконфигурации как и техническая система, в которой, прежде чем отключить старый модуль и подключить новый, необходимо либо отключить источник питания, либо заблокировать прежнюю функцию. Для подключения нового совместимого модуля необходимо, следуя терминологии языка Ада, разобрать программный комплекс на составляющие и отредактировать его заново. В этом смысле язык Ада не предоставляет универсальных средств реконфигурации, подобных тем, которые требуются для динамического подключения только что созданного модуля к уже функционирующей системе. По этой причине на языке Ада нельзя написать операционную систему общего назначения. Однако он прекрасно подходит для создания специализированных систем из набора существовавших ранее модулей.
Индустрия систем программного обеспечения: взгляд в будущее
Язык Ада, позволяющий описывать системы в технических терминах, дает возможность представить себе предприятие по производству систем, на котором как аппаратные, так и программные средства конструируются и описываются единообразно. В этих условиях программирование становится чем-то большим, нежели простое кодирование программных строк, и превращается в процесс структурированного построения систем, в рамках которого программы выстраиваются в структурные сборки из логических черных ящиков, закоммутированных логическими штекерами и кабелями. В таком виде программы могут соответствовать и аппаратным, и программным средствам, н только в теле тех модулей, которые относятся к программному обеспечению, они превращаются в кодированные строки.
Рис. 1.2 иллюстрирует основанное на нашей концепции представление будущего предприятия по производству программного обеспечения. На рис. 1.3 показано, как с помощью языка типа Ады можно осуществлять программно-управляемое проектирование систем. Ключевым моментом такого подхода является концептуальное представление структуры системы, которое он обеспечивает руководителям, разработчикам, конструкторам, поставщикам, потребителям, торговым агентам и клиентам. Таким образом, и представители одной и той же группы спе-
Рис. 1.2. «Фабрика» систем.Рис. 1.2. «Фабрика» систем.на языке Адана языке Адапрограммного й аппаратного обеспечения — язык Адаиспользуется как средство общенияпрограммного й аппаратного обеспечения — язык Адаиспользуется как средство общенияПринятие компромиссных
Рис. 1.2. «Фабрика» систем.
Рис. 1.2. «Фабрика» систем.
на языке Ада
на языке Ада
программного й аппаратного обеспечения — язык Ада
используется как средство общения
программного й аппаратного обеспечения — язык Ада
используется как средство общения
. решений относительноаппаратной и программнойреализации
Рис. 1.3. Место языка Ада ь проектировании систем.
циалистов, участвующих в разработке, и участники различных групп получают возможность обсуждать проект системы в одних и тех же терминах. Общее концептуальное представление используется как основа для обсуждения деталей проекта, графиков работ, потребностей в ресурсах и т. д.
Однако вряд ли правомерно было бы ожидать от всех заинтересованных сторон одинаково свободного владения языком Ада. Поэтому от них требуется лишь умение пользоваться графическими обозначениями основных деталей системного проекта, которые находились бы в прямом соответствии с элементами языка Ада.
В других областях техники графические изображения компонентов системы называются ее эскизами. Основная цель данной книги—разработка графической нотации, которая послужила бы эквивалентом эскизного представления для программно-управляемого системного проектирования.
Отметим в заключение, что описанная выше идея индустриального проектирования систем программного обеспечения предполагает прохождение всех фаз жизненного цикла. Это значит, что в соответствии с описанием жизненного цикла, приведенным в разд. 1.2, должны быть сформулированы все требования к системе еще до начала ее проектирования и реализации. Однако в некоторых прикладных областях уже зарождается новый подход к созданию программного обеспечения, идущий вразрез с концепцией жизненного цикла. Значение этих разработок и их связь с материалом данной книги обсуждаются в следующем подразделе.
Новые методы разработки программного обеспечения
Одним из аспектов, так называемого кризиса программного обеспечения, являются практические трудности воплощения сформулированных технических требований в приемлемые системы без длительных подготовительных этапов и больших затрат, которые неизбежны при следовании концепции жизненного цикла, когда все существенные требования должны быть определены до того как заказчик сможет увидеть какие-то результаты.
Широко используемые языки программирования, подобные языкам Паскаль и Ада, снабжаются трансляторами и ориентируются обычно на реализацию концепции жизненного цикла. В особенности это можно отнести к языку Ада, если учесть включенные в него средства разбиения системы на модули и отделение этапов описания модулей от их детальной реализации. Программные комплексы на языке Ада можно создавать только на основе подробных сведений о технических требовани-
ях к ним, причем любое изменение требований может нарушить их работоспособность.
Однако в реальной жизни наивно ожидать четкого определения и согласования всех требований заказчика к сложной системе до тех пор, пока заказчик не увидит хотя бы частичное их воплощение. Причина этого кроется в неизбежном несовершенстве реально существующих организаций: люди бывают заняты, забывают некоторые подробности или вообще не интересуются ими; те, кому известны требования, не всегда участвуют в их определении, информация в процессе общения теряется. Различного рода оплошности, ошибки и упущения неизбежны, даже если приложить максимум усилий для их предотвращения. Вместе с тем программный комплекс на языке Ада, предназначенный для реализации некоторого требования, из-за упущенной детали может стать неприемлемым. Если же структура модуля, определенная в терминах типов данных, пакетов, задач, их интерфейсов и взаимодействий, становится неадекватной, то приходится модифицировать все модули или же поставлять систему, не отвечающую техническим требованиям.
Очень желательно на ранних стадиях жизненного цикла системы возможно дольше воздерживаться от принятия таких проектных решений, которые в дальнейшем могли бы привести к необходимости крупных переделок в проекте. В идеале любые такие решения хорошо было бы отложить навсегда, предоставив заказчику возможность самому определять свои требования непосредственно в режиме удобного диалога с системой, ориентированной на удовлетворение потребностей пользователя.В некоторых прикладных сферах, например при поиске информации в базах данных, подобный подход постепенно становится все более и более реальным.
В таких областях прикладные программы на языках высокого уровня не должны писаться прикладными программистами и затем транслироваться. Они конструируются высокоорганизованными программными средствами, входящими в состав интерфейса пользователя. Далее эти программы транслируются и выполняются в режиме интерпретации и в конечном итоге при необходимости модифицируются в процессе дальнейшего диалога пользователя с системой. В данном случае развитая возможность определения типов не требуется, поскольку природа объектов программирования может изменяться по мере эволюции самой системы.
Такой подход можно определить как формулирование требований номере получения результатов, поскольку пользователь непосредственно видит результаты, к которым приводят его требования, и имеет возможность уточнять их в интерактивном
режиме для достижения необходимых целей. Этот подход называют также интерактивным макетированием.
Метод, при котором требования формулируются по мере получения результатов, резко контрастирует с более традиционным подходом к разработке систем на основе концепции жизненного цикла, когда технические требования детально формулируются задолго до того, как удается увидеть результаты. Однако описываемый в данном разделе метод в принципе неприменим к задачам, которые не относятся к сфере автоматизации прикладного программирования. Такие задачи должны решаться в основном с ориентацией на концепцию жизненного цикла.
Таким образом, использование языка Ада для описания и проектирования систем не накладывает никаких дополнительных ограничений на гибкость проектных решений по сравнению с органически присущими любому реальному проекту, выполненному на основе концепции жизненного цикла. Однако, каким бы ни был язык проектирования и реализации системы, изменения, вносимые в интерфейсы подсистем на последующих этапах проектирования, могут оказывать влияние на все подсистемы. При этом программирование или конструирование подсистем заново будет определять лишь часть общих затрат, вызванных подобным изменением в большом проекте.
Кустарное и промышленное производство программного обеспечения
Вездесущие персональные ЭВМ делают процесс разработки программного обеспечения доступным практически каждому. Повсеместно начинает развиваться кустарное производство программных средств: пользователи, не являющиеся специалистами в области вычислительной техники, создают на своих персональных ЭВМ (зачастую весьма успешно) прикладное программное обеспечение для собственных нужд или даже на продажу. Такие люди обычно не склонны считать проектирование программ чем-то серьезным. Подобным образом ведут себя студенты, успешно освоившие несколько вводных курсов по программированию и уверенные, что они теперь с успехом смогут выполнять любую программистскую работу. Такое отношение довольно естественно, поскольку программирование может дать само по себе впечатляющие результаты при сравнительно небольших затратах умственного труда на технологию программирования как таковую; достаточно изучить лишь несколько синтаксических правил языка и системных команд. В конце концов, для того чтобы создавать работающие программы, нужно не так уж много знать о самих ЭВМ. На самом элементарном уровне программирование — такое же ремесло, как плот-.
ничье или строительное дело, которому можно обучиться на практике, если только иметь к этому склонность.
Разработчики систем и кустари-программисты так же не похожи друг на друга, как профессионалы (архитекторы и инженеры), проектирующие сложные здания, и домашние умельцы, своими руками мастерящие мебель, дачную постройку или жилой дом. Домашний умелец может выполнить всю работу от начала до конца, затратив минимум усилий на предварительное проектирование, принимая решения по ходу работы и доставая требуемые материалы (доски, кирпичи, гвозди и т. д.) по мере возникновения необходимости. Для успешного выполнения своей задачи домашнему умельцу не нужно обучаться основам архитектуры и конструирования.
Программист-кустарь часто может руководствоваться методикой домашнего умельца, конструируя программу снизу вверх построчно и выбирая проектные решения по ходу работы. В некотором смысле его задача даже проще, чем у домашнего умельца, поскольку может и не понадобиться доставать новые материалы: достаточно мощная ЭВМ всегда предоставляет широкий набор стандартных блоков (машинных команд). Во многих случаях для успешного выполнения своей задачи программисту-кустарю не нужно обладать знаниями в области архитектуры и техники программного обеспечения.
Однако и домашний умелец, и кустарный программист достигнут в конечном итоге тех предельных масштабов и сложности проекта, за которыми уже очень трудно или опасно продолжать работу без специальных знаний в соответствующих областях архитектуры и техники. Этот предел можно охарактеризовать как границу между кустарным и промышленным производством.
Для промышленного производства характерно разнообразие технологий, специалистов и целей, что требует детальной проработки планов в любом проекте еще до начала его реализации. Таким образом, ясно, что предложенные в данной книге методы ориентированы на промышленное производство программного обеспечения. В то же время абсолютно справедливо считать, что составление подробного плана до начала выполнения работ помогает избежать ошибок и повышает производительноств труда при выполнении любого проекта. Таким образом, настоящая книга будет полезна и программистам, разрабатывающим программные средства кустарным способом.
Программа как черный ящик: новаторская концепция
Данная книга ориентирует читателя на то, чтобы он представлял себе программное обеспечение в структурной форме, а не в виде блок-схемы или закодированных строк. В книге
предлагается подход к созданию структурных компонентов систем как черных ящиков, отображаемых с помощью рисунков, которые напоминают конструкторские эскизы. Опыт показывает, что способность мыслить на таком уровне требует от многих программистов значительной перестройки мышления. Особенно это справедливо для программистов, привыкших работать в традиционной среде прикладного программирования, где программы выполняются последовательно под управлением монолитной центральной операционной системы. Данная книга призвана помочь читателю преодолеть барьер рутинного мышления, для чего во второй части книги представлен специальный учебный материал, развивающий необходимые концептуальные представления.
Сущность предлагаемого подхода
• Рассматриваемые в данной книге методы ориентированы на программно-управляемое системное проектирование в соответ-
Рис. 1.4. Три опорных элемента книги.
ствии с концепцией жизненного цикла и «держатся» на трех опорах (рис. 1.4):
Структурное проектирование, представляющее собой методологию построения системных структур на основе моделей информационных потоков.
Объектно-ориентированная графическая нотация и концептуальная модель, служащие для представления системных компонент, их интерфейсов и взаимосвязей и образующие основу структурных графов, известных из структурного проектиро-. вания; язык Ада наполняет их семантическим содержанием^
Собственно язык Ада в той его части, которая предназначена для описания системных объектов, их интерфейсов и взаимодействий. Для целей данной книги язык Ада можно рассматривать как язык Паскаль с добавлением концепций пакетов и задач. В качестве иллюстративных примеров структурного проектирования используются Ада-программы, однако в большинстве случаев читатель, знающий язык Паскаль и имеющий элементарные представления о пакетах и задачах в языке Ада, легко сумеет разобраться в приводимых примерах.
В начале книги каждый из трех опорных элементов, изображенных на рис. 1.4, исследуется настолько подробно, чтобы можно было начать обсуждение примеров. Затем все три элемента используются как основа для рассмотрения нескольких примеров проектирования, иллюстрирующих как сам процесс проектирования, так и его технические аспекты. Ведущую роль в книге играют примеры: результаты и принципы выводятся большей частью из них. Три опоры, изображенные на рис. 1.4, рассматриваются в остальных главах части I и части II. Так, гл. 2 представляет собой введение в язык Ада, построенное по нисходящему принципу. Для читателя, знакомого с Паскалем или любым подобным языком и обладающего достаточной «компьютерной грамотностью», чтобы не испугаться концепции мультизадачного режима, не потребуется дополнительно ничего, кроме этого введения.
Глава 2
Ада — язык системного проектирования
Введение
" Как отмечалось в гл. 1, язык Ада имеет ряд новых свойств, позволяющих проводить идеи модульности и параллельности, Свойственные аппаратному обеспечению. В частности, с помощью языка Ада можно представить систему в виде набора черных ящиков, закоммутированных кабелями, которые включаются в гнезда. Черные ящики — это пакеты и задачи или их комбинации. Гнезда — это спецификации (описания) пакетов или задач, задаваемые независимо от их тела. Параллельность реализуется через организацию задач. Интерфейсы пакетов и задач с внешним окружением выглядят аналогично. Конфигурация систем может быть задана статистически путем установления связей между предварительно оттранслированными черными ящиками через их спецификации.
Ясно, что такие свойства языка Ада делают его весьма полезным для структурного проектирования. В то же время у языка Ада есть и много других новых нетрадиционных особенностей, которые полезно перечислить, объединив их в группы, имеющие отношение к фазам жизненного цикла, концепциям структурного проектирования и техническим свойствам (рис. 2.1). К первой группе относятся те свойства, которые используются в течение всего жизненного цикла процесса проектирования и разработки. Технические свойства — это те, которые были приданы языку для удовлетворения конкретных технических требований. Ни те ни другие не имеют прямого отношения к материалу данной книги и рассматриваются лишь в той мере, в которой они пересекаются со свойствами, используемыми при структурном проектировании. Основное внимание в данной книге сосредоточено на второй группе свойств языка Ада, важных для структурного проектирования.
Рассмотрим рис. 2.1, двигаясь от его середины в направлении свойств, существенных для структурного проектирования. Возможности организации пакетов и раздельного описания уже упоминались выше и вкратце обсуждались. Заложенная в языке возможность нисходящего уточнения описаний позволяет на начальном этапе включать в систему составляющие ее модули просто в виде спецификаций, а их тела разрабатывать затем
Жизненный циклЖизненный циклСтруктурное проектированиеСтруктурное проектированиеРодоеыс списанияРодоеыс списанияНисходящее уточнениеНисходящее уточнениепроцедурпроцедурПакетный ввод-выводПакетный ввод-выводИсключительные ситуацииИсключительные ситуацииТехнические аспектыРис. 2.1. Классификация новых важных отличительных особенностей языка Ада.Технические аспектыРис. 2.1. Классификация новых важных отличительных особенностей языка Ада.СпецификацииСпецификациипредставленияпредставленияОрганизацияОрганизацияпакетовпакетовРаздельныеРаздельныеспецификации и теласпецификации и телаОрганизация прохожденияОрганизация прохождениязадачзадачмеханизм рандевумеханизм рандевудля межзадачныхдля межзадачныхсвязейсвязейСредстваСредстваконструирования системконструирования системСовмещениеСовмещение
Жизненный цикл
Жизненный цикл
Структурное проектирование
Структурное проектирование
Родоеыс списания
Родоеыс списания
Нисходящее уточнение
Нисходящее уточнение
процедур
процедур
Пакетный ввод-вывод
Пакетный ввод-вывод
Исключительные ситуации
Исключительные ситуации
Технические аспекты
Рис. 2.1. Классификация новых важных отличительных особенностей языка Ада.
Технические аспекты
Рис. 2.1. Классификация новых важных отличительных особенностей языка Ада.
Спецификации
Спецификации
представления
представления
Организация
Организация
пакетов
пакетов
Раздельные
Раздельные
спецификации и тела
спецификации и тела
Организация прохождения
Организация прохождения
задач
задач
механизм рандеву
механизм рандеву
для межзадачных
для межзадачных
связей
связей
Средства
Средства
конструирования систем
конструирования систем
Совмещение
Совмещение
отдельно. С помощью этого приема удается удобно представлять внутреннюю структуру сложных модулей, не затемняя сути множеством деталей. Еще одна очень полезная особенность языка — это пакетный ввод-вывод. В языке Ада нет специальных команд или операторов ввода-вывода как таковых: эти процедуры реализуются пакетами. Стандартные пакеты ввода-вывода включаются в систему компилятором, а для специальных целей пользователь может создавать собственные пакеты ввода-вывода. Особую важность с точки зрения структурного проектирования представляет механизм рандеву для организации межзадачных связей в языке Ада. Этот механизм обеспечивает единообразие интерфейсов пакетов и задач. Приведенные пять основных свойств языка Ада лежат в основе предлагаемого в данной книге метода.
Особенности языка Ада, имеющие непосредственное отношение к жизненному циклу,— это наличие средств конструировав
ния систем, позволяющих контролировать соответствие типов при раздельной компиляции; унифицированные блоки, из которых путем параметрической настройки аналогично макроопределениям создаются экземпляры модулей; спецификации представления, указывающие компилятору структуру аппаратной среды; средства совмещения, благодаря которым один идентификатор может иметь альтернативные значения при условии, что компилятор различает их по контексту.
Технические средства обеспечивают организацию прохождения задач и обработку исключительных ситуаций. Организация прохождения задач необходима для обеспечения параллельных процессов в прикладных системах, например при управлении в реальном масштабе времени. И дело здесь не в том, что такая возможность существует в принципе и весьма полезна для структурного проектирования, а в наличии конкретного решения проблемы межзадачных взаимодействий. Что же касается исключительных ситуаций, то они связаны с техническими возможностями контроля сбоев путем обращения вызывающей программы к специальному блоку при возникновении условий, соответствующих предусмотренным ошибкам.
В разд. 2.2 дан построенный по нисходящему принципу обзор основных отличительных особенностей языка Ада, представляющих интерес для разработчика систем. Помимо этого, здесь приводится краткая характеристика языка Ада, включающая анализ его противоречивых свойств и степени пригодности для проектирования и реализации систем.
Нисходящий обзор характерных особенностей языка Ада, важных для разработчика систем
Данный раздел посвящен в основном тем свойствам языка Ада, которые, согласно рис. 2.1, ориентированы на процедуры структурного проектирования. Ниже эти свойства перечислены в порядке их последующего рассмотрения:
организация пакетов,
отделение спецификаций от тел пакетов и задач,
механизм рандеву для межзадачных связей,
уточнение сверху вниз,
пакетный ввод-вывод,
организация прерываний.
Организация пакетов и разделение тел и спецификаций
Понятие пакета графически проиллюстрировано на рис. 2.2. Пакет — это черный ящик, предоставляющий пользователю услуги через интерфейс, определенный с помощью спецификации па-
кета1). Спецификация пакета и тело пакета — совершенно раз-: личные компоненты текста Ада-программы, которые можно при желании компилировать раздельно. Тело пакета скрыто от пользователя, который может использовать пакет только так, как определено в спецификации. Спецификация представляет
Спецификация пакета:Спецификация пакета:через обращения к процедурам сопряжениячерез обращения к процедурам сопряженияпакетов — часть тела; видимость извне обеспечивается. в спецификациипакетов — часть тела; видимость извне обеспечивается. в спецификацииРис. 2.2. Логическая огранизация пакетов.Рис. 2.2. Логическая огранизация пакетов.
Спецификация пакета:
Спецификация пакета:
через обращения к процедурам сопряжения
через обращения к процедурам сопряжения
пакетов — часть тела; видимость извне обеспечивается. в спецификации
пакетов — часть тела; видимость извне обеспечивается. в спецификации
Рис. 2.2. Логическая огранизация пакетов.
Рис. 2.2. Логическая огранизация пакетов.
собой видимый раздел пакета и включает определения, описания и спецификации почти всех возможных элементов Ада- программы. Чаще всего он содержит спецификации подпрограмм, обеспечивающие доступ к выполняемым данным пакетом функциям. В то же время он может содержать определения типов данных, описания информационных объектов, спецификации встроенных пакетов и встроенных задач. Тело — это скрытый раздел пакета. Чаще всего оно состоит из тел подпрограмм, определенных в видимом разделе, и описаний локальных переменных пакета, а также вспомогательных подпрограмм, используемых в видимых подпрограммах. Пакет может включать, кроме того, встроенные пакеты и задачи, а также спецификации инициализации.
На рис. 2.3 приведен характерный пример представления простого пакета STACK (СТЕК) как черного ящика. Это несколько видоизмененный пример аналогичного пакета из справочного руководства по языку Ада. В пакете имеются доступные извне процедуры PUSH (ПРОТОЛКНУТЬ) и POP (ВЫТОЛКНУТЬ) для элементов фиксированных, заранее определенных типов. Эти процедуры инициируют флажки, указывающие
’) Фактически речь идет о пакете программ в обычном смысле этого термина. — Прим. ред.
Структура пользовательского вызова: Г STACK. PUSH (ELEMENT, STATUS),' STACK. POP (ELEMENT .STATUS);Структура пользовательского вызова: Г STACK. PUSH (ELEMENT, STATUS),' STACK. POP (ELEMENT .STATUS);Рис. 2.3. Стековый пакет.Рис. 2.3. Стековый пакет.
Структура пользовательского вызова: Г STACK. PUSH (ELEMENT, STATUS),' STACK. POP (ELEMENT .STATUS);
Структура пользовательского вызова: Г STACK. PUSH (ELEMENT, STATUS),' STACK. POP (ELEMENT .STATUS);
Рис. 2.3. Стековый пакет.
Рис. 2.3. Стековый пакет.
на переполнение или недогрузку стека. Тела процедур PUSH и POP и структура стековых данных, общая для обеих процедур, невидимы пользователю. Идея состоит в том, что пользователям стекового пакета не придется изменять порядок обращения к нему, даже если тело пакета будет модифицировано и приспособлено к различным типам структур стековых данных, например массивам или связным спискам.
Ада-программа, реализующая этот пакет для структур стековых данных типа массивов, приведена на рис. 2.4. Первая часть представляет собой описание глобальных типов, которые используются как в вызывающем модуле, так и в пакете. Отметим, что эти типы можно было бы определить в спецификации пакета, потому что они на самом деле не глобальные, а имеют отношение только к пользователю пакета. Однако они сохранены здесь как глобальные для сравнения в дальнейшем с задачей-стеком.
Спецификация стекового пакета включает спецификации процедур PUSH и POP; эти спецификации состоят всего лишь из имени процедуры и следующих за ним спецификаций ее параметров.
Третий раздел — тело стекового пакета, содержащее массив фиксированного размера для стека и две процедуры PUSH и POP, работающие на этом массиве.
Доступ извне к процедурам PUSH и POP обеспечивается вызовом процедур STACK-PUSH и STACK-POP. Указывая имя пакета и уточняя таким способом обращение, можно получить
— — КОММЕНТАРИЙ
— -ГЛОБАЛЬНЫЕ ТИПЫ, ИСПОЛЬЗУЕМЫЕ
'- - ВЫЗЫВАЮЩЕЙ ПРОГРАММОЙ И ПАКЕТОМ type ELEM is INTEGER;
type STATUS is (OK, UNDERFLOW. OVERFLOW);
'СТЕКОВЫЙ ПАКЕТ ДЛЯ СПЕЦИФИКАЦИИ ПЕРЕМЕННЫХ ТИПА ELEM
СПЕЦИФИКАЦИЯ package STACK is
' procedure PUSH (Erin ELEM; FLAG:out STATUS); procedure POP (E:out ELEM; FLAGrout STATUS);
end STACK;
•ТЕПО
package body STACK is
SIZE: constant INTEGER : = 10;
SPACE: array (1 .. SIZE) of ELEM;
INDEX* INTEGER range 0 .. SIZE : = 0;
procedure PUSH (E : in ELEM, FLAG: out STATUS) ig begin
if INDEX = SIZE then FLAG : = OVERFLOW else
INDEX : = INDEX + 1;
SPACE (INDEX) : = E;
FLAG : - OK;
end if;
end PUSH;
procedure POP (E : out ELEM, FLAG; out STATUS) it begin
if INDEX = 0 then FLAG : = UNDERFLOW
else
E : = SPACE (INDEX);
INDEX : = INDEX - 1;
FLAG :.= OK;
bnd if;
end POP;
end STACK;
СТРУКТУРА ПОЛЬЗОВАТЕЛЬСКОГО ВЫЗОВА STACK.PUSH (ELEMENT, STATUS);
STACK.POP (ELEMENT, STATUS); :
Рис, 2.4, Ада-программа, реализующая стековый пакет.
2 Зак. 455
доступ к любому программному элементу внутри пакета, если только он сделан видимым в спецификации.
Ниже перечислены некоторые ключевые моменты работы с пакетами.
Установление соответствия с помощью КомментариевУстановление соответствия с помощью Комментариев(а) Процедуры с раздельным (б) .Процедура с единственным (е) Приватный ТЙПДанНЫУ доступомметодом доступа и кодом операции 8 {реализованный неверно)^качестве параметра.(а) Процедуры с раздельным (б) .Процедура с единственным (е) Приватный ТЙПДанНЫУ доступомметодом доступа и кодом операции 8 {реализованный неверно)^качестве параметра.Рис. 2.5, Пакеты в языке Паскаль.Рис. 2.5, Пакеты в языке Паскаль.
Установление соответствия с помощью Комментариев
Установление соответствия с помощью Комментариев
(а) Процедуры с раздельным (б) .Процедура с единственным (е) Приватный ТЙПДанНЫУ доступомметодом доступа и кодом операции 8 {реализованный неверно)^
качестве параметра.
(а) Процедуры с раздельным (б) .Процедура с единственным (е) Приватный ТЙПДанНЫУ доступомметодом доступа и кодом операции 8 {реализованный неверно)^
качестве параметра.
Рис. 2.5, Пакеты в языке Паскаль.
Рис. 2.5, Пакеты в языке Паскаль.
Активизация имени пакета обеспечивает доступ ко всем его элементам, поименованным в спецификации.
Спецификация пакета объявляется в программе только один раз, хотя он может быть использован несколькими модулями.
Концепция пакета является почти всеобъемлющей.
Пакеты и их спецификации можно при желании компилировать раздельно.
Чем же отличаются пакеты в языке Ада от средств, которые предоставляют нам более распространенные языки? Возьмем в качестве примера «стандартный» Паскаль. Многие организации расширяли Паскаль в самых разных направлениях, но на сегодня единственное пакетное средство стандартного Паскаля — это процедура. На рис. 2.5 проиллюстрированы способы моделирования Ада-пакетов с помощью процедур Паскаля. Если стремиться к тому, чтобы PUSH и POP были раздельными процедурами, то, как показано на рис. 2.5, а, их компоновка в единый стековый пакет может быть осуществлена путем включения в текст программы соответствующих комментариев. Область, отведенная для стека, должна быть при этом объявлена как глобальные данные, a PUSH и POP — как отдельные процедуры; связь между ними нельзя установить ни с помощью имени, ни даже поместив их рядом в тексте программы. Если же все-таки желательно иметь стековый пакет с единственным именем, то, как показано на рис. 2.5, б, его следует сконструировать в виде процедуры с кодом операции в качестве параметра, который будет указывать требуемое действие. Структура стековых данных должна быть по-прежнему объявлена как гло-
'бальная. И наконец, если нам необходимо создать полную имитацию Ада-пакета и скрыть структуру стековых данных внутри стекового пакета, то мы придем к подходу, отображенному на рис. 2.5, в, который в Паскале недопустим. Все процедуры в Паскале обладают свойством повторной входимости, вследствие чего любые локальные структуры данных уничтожаются после возврата в вызывающую программу. Невозможно, таким образом, обеспечить сохранность элементов, помещенных в стек, до следующего вызова той же процедуры.
Проницательный читатель, наверно, заметит, что рис. 2.5, б для некоторых ситуаций в точности удовлетворяет требованиям, предъявляемым к стеку. Изображенный на этом рисунке стековый пакет представляет собой процедуру в чистом виде, работающую на соответствующих глобальных данных. Именно так работают аппаратные стеки процессора, но, хотя это наблюдение и верно, оно не имеет отношения к делу, поскольку в стандартном Паскале невозможно скрыть данные внутри пакета, а Как раз это требуется во многих случаях.
Механизм рандеву
Рассмотрим теперь еще одну относящуюся к процессу проектирования отличительную особенность языка Ада: механизм рандеву для задач, обеспечивающий их параллельное выполнение. Такая возможность может потребоваться для эффективного использования многопроцессорной системы, однако даже в случае однопроцессорной конфигурации задачи оказываются естественными моделями ситуаций во многих реальных приложениях.
Читатель, знакомый с другими языками параллельного программирования, в которых операционными системами реализуется многозадачный режим, может заинтересоваться, насколько термин задача в языке Ада эквивалентен аналогичному термину в этих средах или используемому в них термину процесс. Ответ состоит в том, что Ада-задачи обладают одним дополнительным совершенно уникальным свойством, а именно: они предоставляют пользователю процедурный интерфейс, полностью аналогичный интерфейсу, который обеспечивается пакетом. Задачи могут иметь входы для обращений из других задач, и эти входы должны описываться в спецификации задачи точно так же, как пакетные процедуры — в спецификации пакета. Хотя обращения и к входам, и к процедурам происходят одинаково, они определяются и реализуются по-разному. Обращения к процедурам выполняются вызывающей программой, а к входам —• вызываемой (принимающей/ программой; в по-
следнем случае вызывающая программа ждет своей очереди в течение так называемого рандеву.-
Таким образом, если рассматривать задачи с входами как черные ящики, то в качестве системных объектов они аналогич-
Рис. 2.6. Традиционный и реализованный в языке Ада подходы к организации прохождения задач.Рис. 2.6. Традиционный и реализованный в языке Ада подходы к организации прохождения задач.ны пакетам с видимыми процедурами. Это позволяет экономнее вводить новые понятия в системном проектировании.
Рис. 2.6. Традиционный и реализованный в языке Ада подходы к организации прохождения задач.
Рис. 2.6. Традиционный и реализованный в языке Ада подходы к организации прохождения задач.
Стандартные языки, такие, как Фортран, обычный Паскаль и многие другие, не предоставляют возможностей для организации многозадачной работы. В тех случаях, когда это требуется, такой режим должна обеспечивать базовая многозадачная операционная система. При этом программы на языке высокого уровня выполняются как прикладные программы, которые по мере необходимости обращаются к операционной системе для межзадачной синхронизации и установления связей. Обращения к операционной системе и механизмы межзадачных связей лежат вне языка высокого уровня. Этот подход проиллюстрирован на рис. 2.6, а. Его основная трудность заключается в логической сложности, поскольку нет единой концептуальной модели для системы в целом, включающей набор прикладных программ и операционную систему.
Что касается языка Ада, то он предоставляет пользователю целостный механизм организации концептуально согласован
ной межзадачной связи, не основанный на явных обращениях к
базовой операционной системе и реализованный исключительно в рамках языка высокого уровня. Как показано на рис. 2.6, б, для этого требуется только базовое ядро, обеспечивающее механизм рандеву. Это базовое ядро невидимо на уров-
не Ада-программы. В действительности возможности, обеспечиваемые ядром, имеются в любой универсальной многозадачной операционной системе и могут использоваться так, как показано на рис. 2.6, а; при этом на уровне Ада-программы воздействие операционной системы неощутимо, по крайней мере в принципе. На самом деле первые реализации Ада-программ
ЗАДАЧА-ПРОИЗВОДИТЕЛЬ Вызов:
BUFFER. READ(CHAR)
Рис. 2.7. Основная форма структурного отображения системы с производящей, потребляющей и буферизующей задачами (графическая нотация гл. 3 используется неполностью),
придется выполнять именно описанным способом. Ясно, что такой подход, предполагающий функционирование сложных языковых средств на основе сложной операционной системы, в общем случае нежелателен и пригоден только как временная мера. Эффективные реализации Ада-программ должны основываться на минимальном ядре или непосредственно на аппаратных средствах, обеспечивающих поддержку механизма рандеву.
Для иллюстрации природы межзадачных связей и использования механизма рандеву рассмотрим пример на рис. 2.7, где показаны взаимодействия между задачей-производителем, буферизующей задачей и задачей-потребителем. Эти задачи изображены в виде черных ящиков и немного напоминают пакеты, за тем исключением, что представлены параллелограммами, а не прямоугольниками, чтобы в символическом отображении подчеркнуть их параллельную природу. На рисунке задача- производитель и задача-потребитель автономны и не имеют входов. Напротив, буферизующая задача имеет входы записи и чтения, которые используются двумя другими задачами. Идея состоит в том, что буферизующая задача сглаживает расхождения между скоростью вывода в задаче-производителе и скоростью ввода, свойственной задаче-потребителю. Проницательный читатель может спросить: «Почему бы не использовать пакет? Для чего нужна задача?» Ответ состоит в том, что в про-
тивном случае задача-производитель и задача-потребитель не будут иметь возможности синхронизировать доступ к буферу и могут одновременно вступить с ним во взаимодействие, вызвав противоречивые изменения в структуре его внутренних данных. Другими словами, буферизующая задача обеспечивает взаимное исключение конфликтов на структурах данных буфера.
Читателям, не знакомым с концепцией задач в языке Ада, буферизующая задача может показаться странной, поскольку большую часть времени она ожидает вызова от других задач. Мы привыкли к тому, что задачи должны быть активными и у них должно быть определенное назначение, например управление машиной или прием сообщений от другой ЭВМ. Не следует, однако, забывать, что любая выполняемая задача должна взаимодействовать с другими задачами. Пример буферизующей задачи служит иллюстрацией механизма согласования связей для задач более общего характера. С учетом этой перспективы тот факт, что буферизующая задача не имеет самостоятельного значения, становится не столь важным. Если бы даже она выполняла какую-то работу, то извне все равно выглядела бы точно так же. В действительности ее внешнее сопряжение является хорошей моделью интерфейсов, которые предоставляются пользователю многими функциональными задачами, приведенными в качестве примеров в последующих главах.
Читатели, знакомые с теорией и практикой параллельного программирования знают, что в других системах существуют свои средства обеспечения синхронизации, например команды проверки и установки признаков, семафоры, условные критические области, мониторы, обмен сообщениями и т. д. В языке Ада для этого требуется использование задач. Явное преимущество этого подхода с точки зрения проектирования заключается в том, что вся деятельность по взаимодействию и синхронизации осуществляется активными программными объектами на одном и том же логическом уровне. Так, синхронизация и взаимодействие явно присутствуют в обращениях программных объектов друг к другу. Здесь нет каких-то скрытых механизмов функционирования, завуалированных сигналами и сообщениями. Другое явное преимущество состоит в уменьшении числа понятий, привлекаемых для описания системы, в которой имеются и пакеты, и задачи. Оба типа объектов предоставляют пользователю сходные внешние интерфейсы.
На рис. 2.8, а приведена спецификация буферизующей задачи и показано, как к ней обращаются задача-производитель и задача-потребитель. На рис. 2.8, б представлен простейший вариант тела буферизующей задачи, которая в данной версии воспринимает один символ от производящей задачи через вход WRITE (ЗАПИСЬ) и затем ждет, пока потребляющая задача
считает его через вход READ (ЧТЕНИЕ), прежде чем вновь воспринять следующий символ от задачи-производителя. С помощью оператора приема ACCEPT буферизующая задача сообщает о своей готовности в данный момент воспринять обращение к входу, имя которого указано в операторе. Если обращение уже произошло, это будет означать, что какая-то задача стоит в очереди, связанной с данным входом, и рандеву состоится немедленно. Если же очередь на данном входе пуста, буферизующая задача ожидает обращения к нему. В случае когда вызывающая программа обращается к входу раньше, чем в буферизующей задаче достигнут соответствующий ему оператор приема, ей приходится «стоять» в очереди до тех пор, пока буферизующая задача не начнет воспринимать обращение к этому входу. Тело буферизующей задачи должно содержать по крайней мере по одному оператору приема для каждого входа, объявленного в ее спецификации; в противном случае программа, вызвавшая этот вход, будет ждать вечно.
Пока рандеву не закончится, вызывающая программа простаивает. Отметим, что ни в одном из этих взаимодействий нет ожидания освобождения ресурсов: когда вызывающая программа ждет во входной очереди окончания рандеву, она не занимает вычислительные ресурсы, как и вызываемая программа, когда она ждет вызова какого-либо из принадлежащих ей входов.
В вызывающей программе механизм рандеву по синтаксической структуре в точности совпадает с вызовом и возвращением из процедуры. Существенное отличие от вызова процедуры состоит в том, что необходимые при вызове входа действия выполняются вызываемой, а не вызывающей задачей, и это может привести в ней к задержкам различной длительности перед возвратом в исходное состояние после вызова.
Ясно, что конкретная реализация механизма взаимодействия, приведенная на рис. 2.8, б, неадекватно решает задачу буферизации, поскольку символы не накапливаются в рамках внутренней структуры данных. На рис. 2.8, в приведена более общая программа, основанная на использовании внутреннего кольцевого буфера. Для вызывающих программ ничего не изменилось, но время простоя из-за буферизующей задачи станет меньше. Тело этой задачи подвергалось значительным изменениям: теперь оно содержит оператор так называемого выборочного ожидания (selective wait), который определяет входы WRITE и READ как альтернативные. Этот оператор, а точнее весь текст между зарезервированными словами select и end select, следует рассматривать как единственную простую инструкцию, которая устанавливает буферизующую задачу в состояние ожидания первого вызова входа WRITE или READ. Производящая и потребляющая задачи могут теперь выпол-
ЗАДАЧА-ПРОИЗВОДИТЕЛЬ loop
ФОРМИРОВАНИЕ
ОЧЕРЕДНОГО СИМВОЛА
BUFFER.WRITEICHAR); end loop;
task body BUFFER is? POOL: CHARACTER: begin
loop
ЗАДАЧА-ПОТРЕБИТЕЛЬ
accept WRITE (C: in СНАЙАСТЁЙ1 d»
loop
BUFFER.READ(CHAR);
ИСПОЛЬЗОВАНИЕ СИМВОЛА
POOL: = C; end;
end loop;
accept READ (C; out CHARACTER) dS
СПЕЦИФИКАЦИЯ БУФЕРА
С : = POOL; end;
task BUFFER is
entry READ (C : out CHARACTER);
entry WRITE (C : in CHARACTER);
end loop;
end BUFFER;
end;
(а) Сопряжения задач.
(б) Буферизующая задача в простейшей форме.?
task body BUFFER is
POOL_SIZE: constant INTEGER : = 100;
POOL s ; array (1.. POOL_SIZE) of CHARACTER;
IN_INDEX, OUT_INDEX: INTEGER range 1.. POOL_SIZE 1 « 11 begin
Joop
select
accept WRITE (C: in CHARACTER) do
POOL (IN_INDEX) : = C;
end;
IN_INDEX : = INJNDEX mod POOL. SIZE + 1>
accept READ (C: out CHARACTER) do
C : = POOL (OUTJNDEX); .
end;
OUTJNDEX : = OUT INDEX mod POOL_SIZE + 1) end select;
end loop;
end BUFFER;
Буферизующая задача с выборочным 1 ожиданием,
task body BUFFER is
POOL_SIZE : constant INTEGER : ь 100;
POOL : array (1 .. POOL_SIZE) of CHARACTER;
COUNT : INTEGER range 0.. POOL_SIZE : = 0;
IN__INDEX, OUTJNOEX : INTEGER range 1.. POOL_SIZE ! ■ 1 begin loop'
select
when COUNT< POOL_SIZE =>
accept WRITE (C : in CHARACTER) do
POOL (IN_INDEX) : = C;
end;
IN_INDEX : = IN_INDEX mod POOL_SIZE + 1;
COUNT ; = COUNT + 1;
or when COUNT > 0 =>
accept READ (C : out CHARACTER) do
C : = POOL (OUT_INDEX);
end;
OUT_INDEX : = OUT_INDEX mod POOL_SIZE + h
COUNT : = COUNT-1;
end select;
end loop;
end loop;
end BUFFER;
Буферизующая задача с механизмом защиты (соответственно справочному руководству по языку Ада),
Рис. 2.8. Трехзадачная Ада-программа с производящей, потребляющей и буферизующей задачами.
пяться независимо, предоставив буферизующей задаче сглаживание любого превышения «производства над потреблением». В данном примере избыточные символы накапливаются в ограниченном кольцевом буфере. Если задача-производитель слишком сильно опередит задачу-потребитель, то кольцевой буфер замкнется и новые данные окажутся записанными поверх старых раньше, чем последние будут считаны задачей-потребителем.
Запись новых данных на место прежних в кольцевом буфере можно предотвратить путем использования еще одного характерного средства языка Ада, которое называется (рис. 2.8, г) предохранителем. Защиту обеспечивают операторы when; в них указаны условия, при которых альтернативы выборочного ожидания открыты для приема. Высказывание, относящееся к выборочному ожиданию, по-прежнему следует рассматривать как простую инструкцию, которая устанавливает состояние ожидания. Во время выполнения этой инструкции происходит провер-
Обозначения :
> <1> <1указывают те моменты времени, когда выполняются важные. действия
> <1
> <1
сплошной линией отмечено время, в течение которого задача выполняется
ЗАДАЧА-ПРОИЗВОДИТЕЛЬ буферизующая задача ЗАДАЧА - ПОТРЕБИТЕЛЬ
РандевуРандевуВызов WRITEВызов WRITEВозвратВозвратt>L-Ожидание▻ г-t>L-Ожидание▻ г-^ Выбор альтернативы Ожидание“1 <] Прием вызова WRITE^ Выбор альтернативы Ожидание“1 <] Прием вызова WRITEКонецКонецВремяВремяВызов WRITEВызов WRITE>>Выбор альтернативы ^ ОжиданиеПрием вызова REAO f>tВыбор альтернативы ^ ОжиданиеПрием вызова REAO f>tРандевуРандевуОжиданиеОжиданиеКонец РандевуКонец Рандеву<] Вызов read Ожидание<] Возврат<] Вызов read Ожидание<] ВозвратVV
Рандеву
Рандеву
Вызов WRITE
Вызов WRITE
Возврат
Возврат
t>L-
Ожидание
▻ г-
t>L-
Ожидание
▻ г-
^ Выбор альтернативы Ожидание
“1 <] Прием вызова WRITE
^ Выбор альтернативы Ожидание
“1 <] Прием вызова WRITE
Конец
Конец
Время
Время
Вызов WRITE
Вызов WRITE
>
>
Выбор альтернативы ^ Ожидание
Прием вызова REAO f>t
Выбор альтернативы ^ Ожидание
Прием вызова REAO f>t
Рандеву
Рандеву
Ожидание
Ожидание
Конец Рандеву
Конец Рандеву
<] Вызов read Ожидание
<] Возврат
<] Вызов read Ожидание
<] Возврат
V
V
Дальнейшее ожиданиеВозвратДальнейшее ожиданиеВозвратВыбор альтернативыПрием вызова WRITEВыбор альтернативыПрием вызова WRITEКонецКонец
Дальнейшее ожидание
Возврат
Дальнейшее ожидание
Возврат
Выбор альтернативы
Прием вызова WRITE
Выбор альтернативы
Прием вызова WRITE
Конец
Конец
^ Выбор альтернативы
Рис, 2.9. Временная диаграмма буферизации при отсутствии закрытых входов.
ка условий защиты с целью выбора входов, открытых для приема. В частности, в данном примере, если значение счетчика COUNT равно размеру пула POOL_SIZE, то для приема будет открыт только вход чтения READ. Это означает, что после вызова входа записи WRITE вызывающая программа будет «стоять» в очереди к этому входу до тех пор, пока в результате изменения условий защиты он не окажется открытым. Заметим, что такое изменение условий может произойти только в результате приема обращения к другому входу. Ситуация, при которой все входы закрыты, означает ошибку программирования.
На рис. 2.9 и 2.10 приведены временные диаграммы, отражающие взаимодействия между производящей, буферизующей и потребляющей задачами в двух случаях: когда все альтернативные входы открыты и когда один альтернативный вход закрыт.
Язык Ада обладает еще рядом свойств, связанных с механизмом рандеву; эти свойства будут введены в рассмотрение
Обозначения:
▻ <1-
ЗАДАЧА-ПРОИЗВОДИТЕЛЬ
указывают те моменты времени, когда выполняются важные действия
сплошной линией отмечено время в течение которого задача выполняется
БУФЕРИЗУЮЩАЯ ЗАДАЧА ЗАДАЧА-ПОТРЕБИТЕЛЬ
Буфер заполнен, поэтому вход 'WR !ТЕ закрыт
Выбор альтернэтисы
Вызов WRITE ^
Ожидание
Прием вызова READ ^_
Ожидание
Конец
Рандеву
Снятие защиты от записи
Ожидание
--■.<1
Время
Вызов READ
Возврат
ВОЗВр^ВОЗВр^Дальнейшее ожиданиеДальнейшее ожиданиеКонецКонец•'.Выбор альтернативы•'.Выбор альтернативы
ВОЗВр^
ВОЗВр^
Дальнейшее ожидание
Дальнейшее ожидание
Конец
Конец
•'.Выбор альтернативы
•'.Выбор альтернативы
Выбор альтернативы
Прием вызова WRITE
Рис. 2.10, Временная диаграмма буферизации при наличии одного закрытого 1 входа.
Рис. 2.11. Организация прохождения задач с помощью процедур на Паскале.
в гл. 3 вместе с расширенной графической нотацией для всех альтернатив.
Сравним теперь подходы к организации прохождения задач в языке Ада и стандартном Паскале. Прежде всего следует отмстить, что в стандартном Паскале нет средств обеспечения параллельности. Для создания параллельных программ стандартный Паскаль можно использовать единственным образом: написать специальные процедуры для организации прохождения задач, которые никогда не смогут быть вызваны и не сумеют осуществить нужного возврата в среде языка высокого уровня. Эти процедуры передаются ядру, которое следит за временем выполнения программ и обеспечивает параллельность с помощью ведущей Паскаль-программы; последняя же инициализирует ядро. В языке высокого уровня предполагается, что все это известно программисту. На рис. 2.11 дана структурная диаграмма, показывающая, как взаимодействуют различные компоненты параллельной системы, написанной на Паскале. Такой подход можно реализовать в любом языке высокого уровня, не обеспечивающем параллельности. Основное требование заключается в том, что текст каждой процедуры должен храниться в ядре таким образом, чтобы код, сгенерированный компилятором языка высокого уровня для каждой задачи, взаимодействовал с соответствующим ей контекстом. Паскаль прекрасно под-
ходит для этого, так как его процедуры повторно входимы и их текст хранится в стеке. С Фортраном дело обстоит сложнее из- за отсутствия свойства повторной входимости.
Обратите внимание, что выполненный средствами языка Ада проект, в котором задачи устанавливают связи во время рандеву, может быть реализован в виде точно такой же системы, какая изображена на рис. 2.11; для этого необходимо подходящим образом использовать возможности языка в отношении синхронизации задач и установления связей. При этом ядро не должно явно использоваться для обеспечения механизма рандеву, поскольку этот механизм относительно легко реализовать с использованием других средств установления межзадачных связей.
Нисходящее уточнение
Следующее относящееся к сфере проектирования свойство языка Ада, которое необходимо обсудить,— это возможность нисходящей разработки Ада-программ. Мы уже видели, что если программе пользователя необходим доступ к пакетам и задачам, ей для этого требуются только спецификации их интерфейсов. А что же можно сказать о вложенных объектах? Предположим, например, что пакет содержит внутренние про-
Рис. 2.12. Схема нисходящего программирования на языке Ада с использованием заглушек.
Пакет АПакет Аpackage body A ispackage В isend В:package body В is separate; —ЗАГЛУШКАpackage body A ispackage В isend В:package body В is separate; —ЗАГЛУШКА
Пакет А
Пакет А
package body A is
package В is
end В:
package body В is separate; —ЗАГЛУШКА
package body A is
package В is
end В:
package body В is separate; —ЗАГЛУШКА
separate (A) package body В is
end B;
цедуры, пакеты н задачи. Обычным правилом для вложения программ является следующее: любой объект должен быть определен до того как будет использован. Это правило справедливо и в языке Ада. Однако требование, устанавливаемое этим
правилом, касается только спецификации, поскольку тело паке
та может определяться и после того как будет использовано в одном контексте со спецификацией, либо его можно оформить
в виде заглушки и определить в дальнейшем при раздельной компиляции. Последний подход проиллюстрирован на рис. 2.12.
НаправлениеНаправлениеЗаголоеок Q запрограммированное после тела РЗаголоеок Q запрограммированное после тела РРис. 2.13. Схема, показывающая ограниченность возможностей нисходящего программирования на Паскале.Рис. 2.13. Схема, показывающая ограниченность возможностей нисходящего программирования на Паскале.В примерах мы будем часто прибегать к такому принципу представления в связи с тем, что он позволяет очень удобно в явном виде разделять текст программы на куски размером в страницу. Читатель, однако, должен учесть, что для нисходящего уточнения в языке Ада нет необходимости в раздельной компиляции.
Направление
Направление
Заголоеок Q запрограммированное после тела Р
Заголоеок Q запрограммированное после тела Р
Рис. 2.13. Схема, показывающая ограниченность возможностей нисходящего программирования на Паскале.
Рис. 2.13. Схема, показывающая ограниченность возможностей нисходящего программирования на Паскале.
Чем же все сказанное отличается от возможностей, пре-
доставляемых широко исполь-
зуемыми языками, такими, например, как стандартный Паскаль? В стандартном Паскале имеется механизм предвари
тельного объявления, позволяющий писать программы, в которых две процедуры вызывают друг друга. Это было бы невозможно,
если бы абсолютно все объекты и действия должны были определяться до того как начнут использоваться. Применяемый
в данном случае принцип иллюстрируется на рис. 2.13, где процедура R вызывает процедуру Р, которая вызывает процедуру Q, а та в свою очередь вызывает процедуру R. Как показано на рис. 2.13, в Паскале это осуществляется так: сначала программируется только заголовок Q, затем полностью программируется Р, после чего — полностью Q и затем программируется R. Однако какая-либо возможность определения тел процедур Р и Q в тексте программы уже после определения тела R отсут
ствует.
Пакетный ввод-вывод
Главная отличительная черта языка Ада, влияющая не только на процесс проектирования, но и на другие области его применения, заключается в том, что в нем отсутствуют специаль-
ные операторы ввода-вывода. Вместо этого ввод-вывод осуществляется с помощью пакетов: либо стандартных, поставляемых вместе с компилятором, либо специальных, написанных пользователем. На рис. 2.14 приведен пример пакета для ввода-вывода файла. Этот пример не требует почти никаких разъяснений,
package 1_ОPACKAGE is
type FILEID is limited private;
procedure OPEN (F : in out FILEID);
procedure CLOSE (F : in out FILEID);
procedure READ (F.: in FILE_ID; ITEM : out INTEGER);
procedure WRITE (F : in FILE_ID; ITEM : in INTEGER); private
type FILE_ID is
.record
INTERNAL_ID : INTEGER : = 0;
end record;
end l_O_PACKAGE;
package body l_O_PACKAGE is
LIMIT : constant: ='200;
type FILEDESCRIPTOR is record .,. end record;
DIRECTORY : array (1.. LIMIT) of FILE_DESCRIPTOR;
procedure OPEN (F; in out FILEID) is... end;
procedure CLOSE (F : in out FILE_ID) is,.. end;
procedure READ (F : in FILEID; ITEM : out INTEGER) is ,., end;
procedure WRITE (F : in FILE_ID; ITEM : in INTEGER) is... end; begin
end l_O_ PACKAGE;
Рис. 2.14. Пакет ввода-вывода файлов (соответственно справочному руковод* ству по языку Ада).
кроме одного нового элемента в спецификации пакета — ограниченного приватного типа данных. Это еще один пример реализации принципа утаивания информации при помощи пакетов. Ясно, что в любом пакете для ввода-вывода файлов имена последних должны быть доступны извне. Вследствие этого структура имени файла должна быть задана в спецификации пакета. Важно, однако, чтобы пользователи не создавали собственных имен файлов и не изменяли имен, имеющихся в пакете. Это достигается путем объявления имени файла как ограниченного приватного типа данных. Пользователь пакета получает доступ к имени файла, только вызвав процедуру OPEN (ОТКРЫТЬ), и может затем использовать это имя при вызове процедур
Задача-обработчик прерываний от клавиатурыЗадача-обработчик прерываний от клавиатурыБолее высокиеБолее высокиеУровни системыУровни системы(а) Концептуальное представление.(а) Концептуальное представление.АппаратныесредстваАппаратныесредстваСимволСимвол
Задача-обработчик прерываний от клавиатуры
Задача-обработчик прерываний от клавиатуры
Более высокие
Более высокие
Уровни системы
Уровни системы
(а) Концептуальное представление.
(а) Концептуальное представление.
Аппаратныесредства
Аппаратныесредства
Символ
Символ
task KB-HANDLER is
entry TAKE (CH : out CHAR);
entry KB-DONE;
for KB-DONE use at 8#100 #;
end KB-HANDLER;
task body KB-HANDLER is
BUF, DBR: CHAR;
for DBR use at 8#177462#;
begin
loop
accept KB-DONE do BUF:=DBR; end;
accept TAKE(CH : out CHAR) do CH:=BUF;end;
end loop
end
(б) Ада-программа (по Пайлу).
Рис. 2.15. Задачи, реализующие обработку прерываний в языке Ада.
Условные обозначения:
КВ — DONE ГОТОВО
TAKE ПРИНЯТЬ
READ и WRITE. Он, однако, не имеет доступа к компонентам переменной типа имени файла и не может выполнять над такими переменными никаких действий. Таким образом, у него нет возможности самостоятельно присваивать значения переменным типа имени файла. Эти значения могут быть получены только как параметры процедур пакета.
Полезно сравнить эту возможность с языками типа стандартного Паскаля, в которых встроенный характер инструкции ввода-вывода ограничивает их гибкость.
Очевидно, что описанный пакетный метод ввода-вывода на уровне языковых средств не решает проблемы непосредственного взаимодействия с аппаратными средствами. Это взаимодей-
ствие должно осуществляться тем или иным способом в теле пакета путем обращения к базовой операционной системе или на основе непосредственной работы с аппаратными средствами. 'А это приводит к необходимости рассмотрения еще одной особенности языка Ада.
Механизм прерываний
В рамках программных средств языка Ада прерывание рассматривается как вызов входа задачи, обрабатывающей сигналы прерываний. Для реализации этого в языке Ада предусмотрены так называемые спецификации представлений, которые позволяют связывать прерывания с входами задач. На этапе логического проектирования детали спецификаций представлений не играют особой роли: достаточно лишь знать, что такая возможность существует. Рис. 2.15 иллюстрирует этот подход на примере задачи, обрабатывающей прерывания от клавиатуры.
Заключительные замечания
Остальные особенности языка Ада не столь существенны для проектирования как те, которые были рассмотрены в этом подразделе, хотя, конечно, их тоже можно использовать. Они будут разобраны на примерах там, где это уместно.
Необходимо еще раз подчеркнуть, что для целей проектирования язык Ада можно рассматривать по сути как Паскаль, но с некоторыми специальными дополнительными возможностями. Ада, конечно, отличается в деталях от стандартного Паскаля, но для читателей, знакомых с Паскалем, смысл конструкций языка Ада будет очевиден.
2.3. Критический анализ языка Ада
В заключение рассмотрим положительные и отрицательные стороны применения языка Ада для проектирования и реализации систем.
Ада как язык проектирования систем
С помощью языка Ада различные типы программных модулей удобно представлять в виде черных ящиков. Пакеты и задачи сравнительно просто интерпретировать как на аппаратном, так и на программном уровне, благодаря единообразию принципов и разделению спецификаций объектов и их тел.
Сведение взаимодействия между параллельными компонентами программы к механизму рандеву обеспечивает ясность и единообразие спецификаций, что уже само по себе является значительным преимуществом, так как отсутствуют косвенные взаимодействия, скрытые за сигналами и сообщениями. Если непосредственное взаимодействие между задачами нежелательно, должна вводиться третья задача для обработки косвенных взаимодействий. При этом природа взаимодействий становится явно видимой.
Читатели, придающие большое значение аспектам эффективности, должны отметить, что вспомогательные задачи, управляющие взаимодействиями, совсем не обязательно реализовывать в виде задач, если объектная среда проектируемой системы отлична от языка Ада. В такой среде задача, которая только принимает вызовы от других задач, а сама не выполняет никаких обращений, может быть эффективно реализована хорошо известным способом — путем организации критической области совместно используемой памяти. Разработчик может отметить желательность именно такой реализации в описании системы на языке Ада с помощью указания критической области (формально указание в языке Ада содержит инструкцию для компилятора, однако при проектировании его можно интерпретировать как инструкцию разработчику). Существует также возможность использования подобного указания компилятором языка Ада для обеспечения генерации эффективного кода.
Язык Ада предоставляет возможность нисходящей конкретизации вложенных модулей программного текста, а это облегчает и проектирование программы, и чтение текста.
В случае применения языка Ада можно отсрочить принятие окончательного решения относительно требуемой конфигурации аппаратных средств проектируемой системы; это следует из разумного предположения о том, что логическая архитектура естественным образом отображается на любые физические конфигурации объектных аппаратных средств. Например, если проект включает только две задачи, его очень трудно воплотить в аппаратную конфигурацию, насчитывающую 10 процессоров. В то же время проект, включающий 30 задач, можно очень легко отобразить на 10 процессоров. Все это справедливо независимо от языка Ада, а для последнего более характерно то, что проект, предусматривающий совместное использование пакетов несколькими задачами, сложно отобразить на распределенную среду. Однако механизм рандеву реализуется в ней чрезвычайно просто. Подробнее все эти вопросы будут рассмотрены в части III.
Ожидаемый высокий уровень стандартизации языка и предсказываемое широкое распространение его среди программистов тоже следует отнести к положительным моментам.
Ада как язык реализации систем
Ада в качестве языка реализации вызывает довольно противоречивые мнения. Основные заслуживающие внимания критические замечания касаются аспектов сложности, надежности и возможности обработки данных в реальном времени.
Несомненно то, что у этого языка много полезных особенностей, что он предоставляет очень мощные средства и, следовательно, его труднее изучить, чем любой другой современный язык программирования. Однако его наверняка легче освоить, чем существующие в настоящее время комбинации из стандартных языков и многозадачных операционных систем. Более того, если требуются не все свойства языка Ада, можно прийти к соглашению об использовании его определенных подмножеств, и организации, в которых программируют на языке Ада, могут установить стандарты, ограничивающие использование некоторых его свойств. Такие ограничения можно ввести принудитель-. но с помощью препроцессора.
Вопросы, касающиеся надежности, возникают частично из- за масштабов и сложности языка и частично из-за того, что некоторые его конкретные элементы по предположению могут взаимодействовать ненадежно. Например, организация динамического прохождения задач и обработка исключительных ситуаций сами по себе представляют сложные элементы языка, и вполне возможно, что нерегламентированное использование их сочетаний приведет к созданию программ, правильность которых трудно гарантировать.
Сомнения относительно способности языка Ада обеспечить организацию взаимодействий в реальном времени возникают из-за того, что единственным механизмом взаимодействий между параллельными компонентами системы является рандеву. В явном виде отсутствуют средства защиты памяти наподобие семафоров или проверяемых условий, на базе которых можно было бы организовать эффективное коллективное использование критических областей памяти параллельными компонентами. Затруднение здесь состоит в том, что в среде, где несколько задач выполняются одним процессором, вынужденные излишние переключения контекстов задач для обеспечения условий рандеву увеличивают время реакции системы при работе в реальном масштабе времени. По мнению автора, в будущем это обстоятельство перестанет быть серьезной проблемой, поскольку компиляторы с развитой логикой, возможно оснащенные
соответствующим набором указаний, смогут генерировать эффективные коды, ориентированные на конкретную конфигурацию системы.
В своем знаменитом (или печально знаменитом) обращении к членам Ассоциации по вычислительной технике Хоар высказывает крайне негативное мнение об Аде как языке реализации систем. По его мнению, этот язык нельзя использовать в тех прикладных областях, где важно обеспечить безопасность человека. С учетом нынешнего практического состояния дел автор считает подобную критику в адрес языка программирования несправедливой, так как обеспечение безопасности сложной технической системы требует гораздо более широкого арсенала средств, чем просто язык программирования. В конечном итоге эта безопасность независимо от используемого языка программирования определяется дальновидностью и компетентностью разработчиков и конструкторов в самых различных областях, и программные средства — лишь одна из них. Язык программирования— это не более чем инструмент для реализации программной части системы. Как и любой инструмент, его можно использовать хорошо или плохо.
По-видимому, язык Ада, если его использовать правильно, представляет собой более совершенный инструмент для реализации программного обеспечения, чем языки, существовавшие до сих пор. Однако, по мнению автора, истинное преимущество языка Ада состоит в том, что он способствует сближению в концептуальном плане процессов проектирования и реализации систем. В руках компетентных профессионалов это наверняка приведет в будущем к положительным результатам в части безопасности и надежности систем.
Заключение
Общие концепции языка Ада — прекрасная основа для системного проектирования. Высокий уровень стандартизации этого языка и его ожидаемое широкое распространение также оправдывают его использование в системном проектировании. Следуя методологии проектирования, основанной на некотором подмножестве языка Ада, можно избежать при проектировании излишней детализации. В последующих главах книги излагается именно такая методология, опирающаяся на применение графической нотации, в которой отражаются существенные концепции языка и игнорируются несущественные подробности.
Часть II
Введение в логическое проектирование
В этой части книги сначала при помощи графических методов проводится исследование структурных компонентов систем, проектируемых средствами языка Ада. Затем описывается неформальная методология проектирования систем. Основные аспекты этой методологии, основанной на знании системных структур, иллюстрируются на примерах создания проектов трех сравнительно не сложных для понимания систем.
Глава 3
Проектно-ориентированная методика наглядного описания систем
Вводные замечания
Всем известно, что «лучше один раз увидеть, чем сто раз услышать», а математики, например, знают, что удачные обозначения могут даже подсказать решение задачи. С учетом этого в данной главе излагается подход к описанию архитектуры систем, основанный на использовании рисунков и хорошо подобранных символических обозначений для привлекаемых понятий языка Ада. Однако для чтения этой главы, в которой новые концепции вводятся по аналогии с хорошо знакомыми, не связанными с программированием примерами, требуется иметь лишь общее представление о языке Ада. Рассматриваемая методика описания систем охватывает сложную концепцию параллельности процессов, однако изложение этой концепции носит учебный характер и должно быть доступно читателям, не имеющим солидной подготовки в этой области.
В разд. 3.2 приведена графическая нотация для описания архитектуры систем с использованием аналогий между организацией прохождения задач в среде языка Ада и человеческой деятельностью, предусматривающей взаимодействия; хорошо подготовленный читатель может пропустить подразд. 3.2,2, в котором рассматриваются эти аналогии.
В разд. 3.3 с использованием введенной графической нотации разрабатывается «набор деталей конструктора» стандартных системных структур. Здесь охватываются как последовательные, так и параллельные системы, приводятся решения основных задач, возникающих в параллельных системах, — разрешения конфликтов, синхронизации, планирования и блокировки.
В разд. 3.4 устанавливается связь между концепциями данной главы и языком Ада. Разд. 3.5 содержит основные выводы по материалу главы.
Средства наглядного описания архитектуры систем
Графическая нотация
На рис. 3.1 приведены основные графические символы: четырехугольные блоки представляют пакеты и задачи; стрелки — допустимые связи и потоки информации; символ овальной формы — данные. Для модулей, сущность которых еще не определена, полезно ввести специальный символ в виде облачка.
С помощью этих символов можно строить потоковые и структурные графы. Потоковые графы идентифицируют модули и показывают их информационные, но не управляющие взаимодействия. В структурном графе отражены оба типа взаимодействий.
Четырехугольники, отображающие пакеты и задачи, нарисованы по-разному для того, чтобы символически отразить их основное различие. Пакеты представлены прямоугольниками, а задачи — параллелограммами, что подчеркивает их параллельный характер.
Символические обозначения пакетов и задач отражают не только различия между ними, но и их сходство. Четырехугольники символизируют близость концепции пакетов и задач к понятию черного ящика. Маленькие четырехугольники, нарисованные по краю большого, изображают контактные «гнезда», с помощью которых пользователь «подключается» к черному ящику. Отметим, что в языке Ада нет термина «гнездо». Этот термин используется здесь только для того, чтобы подчеркнуть общность свойств интерфейсов пакетов и задач. В обоих случаях, если применять терминологию аппаратных средств, требуется совместимость на уровне разъемов. Другими словами, при использовании пакетов и задач, а также при определении их тел должно обеспечиваться выполнение требований спецификаций интерфейса, которые и определяют основные свойства гнезд. .
Пакет с процедурными "гнездами"
Пакет с непроцедурным "гнездом"
Задача с "гнездами" входов
Соединительная связь (вызов процедуры, вызов входа, доступ к информации)
0-0-Очередность доступа (для случаев, когда связи не упо* рядочены сверху вниз или слева направо)Очередность доступа (для случаев, когда связи не упо* рядочены сверху вниз или слева направо)Поток данныхПоток данных
0-
0-
Очередность доступа (для случаев, когда связи не упо* рядочены сверху вниз или слева направо)
Очередность доступа (для случаев, когда связи не упо* рядочены сверху вниз или слева направо)
Поток данных
Поток данных
О
Не до конца определенный модуль (называемый облачком, пузырьком, аморфным концептуальным элементом или функциональной единицей)
Рис. 3.1. Основные условные графические обозначения для описания архитек- туры систем.
Связь между пакетом или задачей и ее потребителем изображается стрелкой, проведенной от блока потребителя к соответствующему гнезду того блока, к которому организуется доступ. Отметим, что доступ здесь приобретает наглядную интерпретацию, указывающую на связь между двумя модулями. При этом не подразумевается использование принятых в языке Ада переменных доступа.
В обоих случаях в спецификациях интерфейса описывается только способ подключения к черному ящику. В них не указываются связи, идущие от черных ящиков, и не перечисляются потребители.
Связи с пакетами могут быть процедурными и непроцедурными. Процедурные связи соответствуют вызовам обыкновенных процедур, объявленных в спецификации пакета. Непроцедурные связи указывают на доступ к другим внутренним элементам пакета, например к внутренним переменным, объявленным в его спецификации.
Изолированные процедуры изображаются в виде прямоугольных блоков без гнезд; их можно рассматривать как вырожденные пакеты.
Гнезда задач, известные в языке Ада как входы, с точки зрения пользователя сходны с пакетными процедурами. Действительно, если какая-либо задача всегда вызывается не более чем одной задачей, то ее функционально можно представить пакетом, у которого входы заменены процедурами. Наоборот, пакет, процедуры которого могут вызываться несколькими задачами без наложения их друг на друга, в функциональном отношении можно заменить задачей, у которой вместо процедур будут входы.
Существенная разница с точки зрения пользователя между процедурным доступом к пакетам и доступом к задачам через входы состоит в обеспечении разрешения конфликтов и синхронизации, а не в функциональных особенностях. Механизм рандеву заключается в том, что вызывающая задача встречается с вызываемой и затем ждет, пока вызываемая задача обслужит вызов. Если вызываемая задача занята выполнением собственной работы или взаимодействует с другой задачей, она не может принять очередной вызов. При этом новые абоненты должны ожидать в очереди, соответствующей данному входу. Это обеспечивает взаимоисключающую обработку вызовов, поступающих от различных задач. В вызывающей задаче такой механизм тоже требует синхронизации, поскольку ожидание возврата после вызова может продлиться непредсказуемо долго.
Приведенные на рис. 3.1 символы не охватывают всех возможных случаев. В частности, механизм рандеву имеет ряд вариантов, которые необходимо различать при проектировании с помощью различных обозначений.
В дальнейшем читатель должен считать (если не оговорено обратное), что во всех задачах выполняется бесконечный цикл. Тогда показанные на рисунках схемы вызовов и операции их обработки можно рассматривать как совокупность событий, имеющих место в течение одного цикла.
Безусловный вызов
Условный вызов
ALTERNATIVE.. ACTION; end select;
Стандартный вход
ALTERNATIVE...ACTION; end select;
Рис. 3.2. Обозначения на структурном графе различных вариантов обращений к входу.
На рис. 3.2 и 3.3 иллюстрируются различные варианты рандеву и приводятся соответствующие им графические обозначения. Как показано на этих рисунках, вызовы входов разделяются на безусловные, условные и временные, а их прием может происходить в фиксированном порядке, в порядке поступления (первым пришел — первым обслужен) или в зависимости от определенных условий. Вызываемая задача может также прекратить ожидание вызова входа по истечении установленного интервала времени.
На рис, 3.2 изображен новый символ со стрелкой, загнутой назад, которая означает, что вызывающая задача не может ждать приема вызова неопределенно долго. Эта особенность задачи может выражаться в двух формах. Если задержка вообще недопустима, то вызов называется условным, и альтернативные действия (ALTERNATIVE-ACTION)’ задаются в операторе ELSE. Если же допускается задержка на время Т, то вызов называется временным, а допустимое время задержки Т
(а) Фиксированный порядок. •(а) Фиксированный порядок. •^accept A do ... end; - - КРИТИЧЕСКАЯ СЕКЦИЯ OTHER_A„PROCESSING;oraccept В do... end; - - КРИТИЧЕСКАЯ СЕКЦИЯother_b„processing;end select;^accept A do ... end; - - КРИТИЧЕСКАЯ СЕКЦИЯ OTHER_A„PROCESSING;oraccept В do... end; - - КРИТИЧЕСКАЯ СЕКЦИЯother_b„processing;end select;
(а) Фиксированный порядок. •
(а) Фиксированный порядок. •
^accept A do ... end; - - КРИТИЧЕСКАЯ СЕКЦИЯ OTHER_A„PROCESSING;
or
accept В do... end; - - КРИТИЧЕСКАЯ СЕКЦИЯ
other_b„processing;
end select;
^accept A do ... end; - - КРИТИЧЕСКАЯ СЕКЦИЯ OTHER_A„PROCESSING;
or
accept В do... end; - - КРИТИЧЕСКАЯ СЕКЦИЯ
other_b„processing;
end select;
accept A;do... end; — КРИТИЧЕСКАЯ СЕКЦИРГ
OTHER_A_PROCESSING:
accept B; do... end; - - КРИТИЧЕСКАЯ СЕКЦИЯ OTHERS „PROCESSING;
В порядке поступления (выборочное ожидание) •'
select
when х = >
, accept A do... end; - - КРИТИЧЕСКАЯ СЕКЦИЯ' OTHER_A_PROCESSING;
or
when у = >> t
accept В do... end; - - КРИТИЧЕСКАЯ СЕКЦИЯ OTHER_B_PROCESSING;
end select;
Обусловленный порядок,
accept Ado.., end; — - КРИТИЧЕСКАЯ СЕКЦИЯ
• OTHER_A_PROCESS|NG; or
accept BJo... end; - - КРИТИЧЕСКАЯ СЕКЦИЯ OTHER_B„PROCESSING;
delay T;
DELAY_PROCESSING;
end select;
С выделением лимита времени. .
Рис. 3.3. Обозначения на структурном графе различных вариантов выполнения оператора приема при вызове входа. (Замечание: точки означают нали- ,чие защиты; относящееся к точке пояснение указывает условие, при котором данный вход закрыт.)
устанавливается в операторе OR. В обоих случаях могут выполняться альтернативные действия.
Для наглядного представления входов, обращения к которым принимаются в фиксированном порядке, на структурном графе стрелки доступа либо перечеркиваются ориентированной дугой, направление которой соответствует порядку приема вызовов, либо нумеруются в заданном порядке (рис. 3.3, а). Если обращения к входам принимаются по принципу выбора с ожиданием в соответствии с дисциплиной «первым пришел — первым обслужен» (т. е. в порядке поступления), то, как показано на рис. 3.3, б, совокупность гнезд, соответствующих этим входам, охватывается контуром или перечеркивается. Входы, которые игнорируются до тех пор, пока не будет снята защита, помечаются точкой, располагаемой рядом со стрелкой доступа (рис. 3.3,в). Возможность выхода из состояния выборочного ожидания по превышению лимита времени отображается с помощью гнезда-псевдовхода, обеспечивающего выполнение альтернативных действий при возникновении задержки (рис. 3.3, г). Для вызываемой задачи наличие такой альтернативы означает еще один вход. Его можно интерпретировать как вход, к кото-, рому обращается система, управляющая прохождением задач.
Оператор отбора на рис. 3.3, б указывает на то, что задача, к которой происходит обращение, ожидает вызова любого из ее входов А или В; если вызовы входов А и В поступают одновременно, то один из них выбирается случайным образом. После того как вызов произошел и принят, рандеву продолжается до тех пор, пока в вызванной задаче не будет достигнут, оператор END. Это так называемая критическая секция задачи. После окончания выполнения критической секции, но еще до выхода из оператора выборочного ожидания допускается дальнейшая работа вызванной задачи, связанная с данным входом '(OTHER_A_PROCESSING, OTHER_B_PROCESSING).
Изучая символику рис. 3.3,6, необходимо ясно понимать, что ожидание вызова входа, реализуемое оператором отбора, не есть ожидание освобождения ресурсов. Форма записи оператора отбора, в которой разделителем списка альтернатив служит слово OR, может привести читателя к ошибочному представлению о том, что эти альтернативы все время опрашиваются, пока не произойдет обращение к одной из них. Такое представление чрезвычайно далеко от истины. На самом деле оператор отбора со всеми его альтернативами следует рассматривать как элементарную команду, задающую сложное условие ожидания. На время ожидания выполнение вызванной задачи задерживается.
В операторе WHEN на рис. 3.3, в используется переменная X, которая не позволяет принять обращение к входу А до тех
пор, пока X не примет значения «истина». Эта защитная блокировка снимается при обработке обращения к какому-либо другому входу в пределах того же оператора выборочного ожидания или в результате вызова входа другой задачи.
В связи с символикой рис. 3.3 следует запомнить, что защита входов устанавливается при активизации оператора отбора и никак не изменяется в течение всего периода пребывания задачи в состоянии ожидания.
По поводу любого из рис. 3.3, б—г необходимо четко усвоить, что каждый раз при активизации оператора отбора при- римается только один вызов входа. Обычно после выполнения обращения вызванная задача снова активизирует оператор отбора, переходит в состояние ожидания очередного вызова входа и т. д. до бесконечности.
Возможные задержки, возникающие при взаимодействии задач, можно классифицировать следующим образом:
В вызывающей и вызываемой задачах могут возникать структурные задержки как следствие либо фиксированного, либо обусловленного порядка выполнения операторов приема. Эти задержки зависят от структуры взаимодействий между задачами. Возможность их возникновения ясно прослеживается на структурном графе.
■ 2. В вызывающей задаче могут возникать задержки по перегрузке из-за наличия очередей обращений к входам. Эти задержки определяются количеством вызывающих задач и частотой вызовов. Следовательно, возможность возникновения задержек по перегрузке тоже прослеживается в явном виде на структурном графе.
В вызывающей и вызываемой задачах могут иметь место скрытые задержки даже при отсутствии задержек структурного характера или связанных с перегруженностью системы. Они могут возникать или из-за того, что вызванная задача еще не достигла соответствующего оператора приема в тот момент, когда произошло обращение к ее входу, или же вследствие того, что некоторое обращение к входу оказалось принятым до того как в вызывающей задаче осуществлен вызов входа. В любой разумно спроектированной системе скрытые задержки должны быть небольшими. На системном структурном графе этот тип задержек не виден.
Рис. 3.4 иллюстрирует применение некоторых введенных выше символов для описания систем. На рис. 3.4, а представлен граф потоков данных, на котором отображены только информационные потоки между модулями и не показаны связи по обращениям. В этом графе могут быть любые модули из дисла изображенных на рис. 3.1.
Рис. 3.4. Примеры использования графической нотации.
На рис. 3.4, б представлен структурный граф, на котором показаны действующие связи между модулями и информационные потоки между ними. Этот граф отображает статическую картину структуры системы и включает как управляющие, так и информационные взаимодействия. Он дает также некоторое представление об упорядочении взаимодействий во времени.
Пакеты и задачи могут быть произвольно связанными между собой и встроенными, как показано на рис. 3.5. Необходимо только следить за тем, чтобы в случае, когда к одному пакету обращаются сразу несколько задач, эти задачи не мешали
Рис. 3.5. Пакеты и задачи; встроенные, независимые и коллективного пользования.
друг другу. Эта проблема проектирования освещается в разд. 3.2.
Полезно различать пассивные и активные пакеты (рис. 3.5). Пассивный пакет не содержит встроенных задач; в активном пакете они есть и могут быть скрыты за спецификацией пакетного интерфейса.
Введенная нами графическая нотация позволяет представлять систему как совокупность аппаратных средств, т, е. в ви-
де набора черных ящиков, закоммутированных друг с другом с помощью штекеров и гнезд. Однако такое условное представление весьма статично и пригодно в основном лишь для наглядного отображения взаимосвязей. Для того чтобы наглядно представить функционирование системы в динамике с учетом возможной параллельности процессов, необходимы какие-либо средства динамического отображения систем. Именно этому вопросу посвящен следующий раздел.
Средства отображения динамики прохождения задач в языке Ада по аналогии с взаимодействиями между людьми
Наша цель здесь состоит в том, чтобы помочь читателю перенести его представления о взаимодействиях между людьми и их организациями в область разработки способов отображения динамического механизма прохождения задач в Ада-про- граммах.
Представьте себе, что структурный граф системы описывает статическую физическую структуру делового учреждения, где помещения, в которых находятся люди, связаны коридорами и дверными проемами. Проводя аналогии со средствами языка Ада, самих людей в данном случае можно уподобить задачам, коридоры — путям доступа, а рабочие кабинеты и их входы — интерфейсам задач или активных пакетов. Проход по коридору к какому-нибудь кабинету аналогичен обращению к входу задачи или к некоторой процедуре активного пакета. Ожидание своей очереди у двери кабинета и получение затем нужных услуг соответствует механизму рандеву. Использование таких пассивных средств, как диктофон, текстовый процессор или картотечный шкаф, соответствует обращению к пассивному пакету.
Небольшая часть структуры учреждения изображена в виде структурного графа на рис. 3.6, где представлены неформальное описание поведения людей с помощью схематических фигурок (рис. 3.6, а) и аналогичное по используемым изобразительным средствам описание системы в среде языка Ада (рис. 3.6,6). На данном графе показан набор возможных способов обращения людей друг к другу и проведения рандеву между ними (как между задачами), а также ряд пассивных черных ящиков (пассивных пакетов), отображающих обстановку типичного учреждения. Отметим, что данная структура не обязательно наилучшая: это всего лишь один из многих вариантов. На рисунке отмечены пять сотрудников фирмы: вицепрезидент, два управляющих, секретарь и помощник одного из управляющих. Показаны также три пассивных черных ящика,
которые в данном конкретном примере представляют собой картотечные шкафы. Аналогия между черными ящиками и пакетами, между людьми и задачами является полной в том смысле, который мы в них вкладываем, поэтому далее для большей ясности изложения будем говорить только о пакетах и задачах.
Рассмотрим сначала одну из задач вице-президента. Он имеет совершенно свободный доступ к личной картотеке и может пользоваться ею без согласования своих действий с потребностями каких-либо других задач. Он может также решить обратиться к более широкой картотеке, например к картотеке сотрудников фирмы, и затем провести рандеву с одним из своих управляющих, для того чтобы передать ему управление картотекой. Стрелка, идущая от задачи вице-президента к управляющему по кадрам, означает приход вице-президента в
1(a) Неформализованное описание.
(6) Описание на языке Ада.
Рис. 3.6. Фрагменты структурного графа учреждения.
Условные PUT
GET
DO IT PICKUP DEPOSIT
обозначения: ПОМЕСТИТЬ ПОЛУЧИТЬ ВЫПОЛНИТЬ ВЗЯТЬ ПЕРЕДАТЬ
3 Зак. 455
кабинет этого управляющего для рандеву. Здесь рандеву используется для того, чтобы поручить вызванной задаче выполнить услугу для вызывающей. Обратившаяся за услугой задача называет требуемый вид обслуживания. В данном случае— это обработка картотеки сотрудников. Одновременно вызванной задаче могут быть переданы необходимые параметры, например фамилия сотрудника, карточку которого следует обработать, и тип требуемой операции обработки. В общем случае рандеву можно использовать для пересылки параметров и
task body VICE-PRESIDENT istask body VICE-PRESIDENT isbeginloopPRIVATE_FILE.GET (...);PRIVATE_FILE.PUT (.,.);PERSONNEL_FILE.PUT (...);PERSONNEL_MANAGER.DO_IT (.,.);beginloopPRIVATE_FILE.GET (...);PRIVATE_FILE.PUT (.,.);PERSONNEL_FILE.PUT (...);PERSONNEL_MANAGER.DO_IT (.,.);end loop;end loop;данных в любом направлении. Пока длится рандеву, в состоя-
task body VICE-PRESIDENT is
task body VICE-PRESIDENT is
begin
loop
PRIVATE_FILE.GET (...);
PRIVATE_FILE.PUT (.,.);
PERSONNEL_FILE.PUT (...);
PERSONNEL_MANAGER.DO_IT (.,.);
begin
loop
PRIVATE_FILE.GET (...);
PRIVATE_FILE.PUT (.,.);
PERSONNEL_FILE.PUT (...);
PERSONNEL_MANAGER.DO_IT (.,.);
end loop;
end loop;
нии ожидания находится вызывающая задача, но начала рандеву может ожидать любая из двух задач. Например, может оказаться, что вице-президенту придется ждать, пока управляющий отреагирует на его обращение, или управляющий, которому, возможно, предстоит
вызов к вице-президенту, вынужден будет ожидать, пока
end VICE-PRESIDENT;совершится это событие, и
Рис. 3.7. Скелет Ада-программы для лишь после этого сможет на задачи вице-президента.него отреагировать (пойти на
прием).
В данном конкретном примере задача вице-президента име
ет доступ к трем модулям, а именно к двум пассивным пакетам и одной задаче. Из структурной диаграммы можно получить много информации об упорядочении этих обращений во времени.
Скелет Ада-программы для задачи вице-президента дан на рис. 3.7. Термин скелет означает наличие в схеме только основных логических элементов программы без ненужных деталей. Подобные скелеты программ иногда бывают полезным инструментальным средством проектирования и описания. Отметим, однако, что в данном случае вся информация, содержащаяся в скелете программы, имеется в более компактной форме и на структурном графе.
Рассмотрим теперь задачу управляющего по кадрам. Он ждет вызова от вице-президента и затем обрабатывает карточку названного сотрудника. Приведенные здесь взаимодействия, включающие работу с общедоступной картотекой, в терминах
программирования, как и в жизни, описываются довольно замысловато; это объясняется тем, что управление общедоступным пакетом следует передавать от задачи к задаче с боль-
щой осторожностью. Например, вице-президент не должен вносить изменений в конкретную карточку ни после того как он попросил управляющего по кадрам обработать этот документ, ни до того как управляющий информировал его о завершении порученной работы.
Допустим, что для обработки карточки сотрудника управляющий по кадрам должен выполнить следующие операции: извлечь указанный документ, выбрать из него и отпечатать необходимые сведения, передать эту информацию управляющему соответствующего отдела и попросить своего помощника, чтобы он проследил за дальнейшими действиями. Возможно, управляющий по кадрам предпочтет непосредственно обратиться к машинописному бюро и к своему помощнику, зная, что здесь ему не придется долго ждать. Однако прямое взаимодействие с нужным управляющим может оказаться неудобным по причине его обычной занятости. Поэтому управляющий по кадрам может принять решение провести рандеву с секретарем нужного руководителя и передать для него сообщение. Когда управляющий будет иметь рандеву со своим секретарем по поводу этого сообщения—до или после того как оно передано, — для управляющего по кадрам значения не имеет; в любом случае он может рассчитывать на то, что документ в конечном счете поступит по назначению. Скелет Ада-программы для задачи управляющего по кадрам приведен на рис. 3.8.
Секретарь оказывает услуги по хранению поступающей от различных управляющих информации в картотеке сообщений и по передаче этих сведений другим управляющим, когда это потребуется. Секретарь сам не является инициатором рандеву, но участвует во многих из них, принимая запросы на обслуживание. На рис. 3.9 представлен скелет Ада-программы для задачи секретаря.
Что касается помощника управляющего по кадрам, то он просто ждет указаний от своего руководителя и затем выполняет их (соответствующие операции на диаграмме не показаны).
Управляющий отделом принимает сообщения от секретаря, инициируя рандеву с ним, а затем реализует собственные функции, не показанные на структурной диаграмме.
Рассмотрим теперь взаимодействие между управляющим по кадрам и машинописным бюро. Управляющий по кадрам должен иметь возможность поручить печать нужного документа любой из свободных машинисток, а те в свою очередь должны иметь возможность оповещать клиентов о своей готовности выполнить работу. В организационных системах существуют два принципа подобных взаимодействий:
координация с помощью третьего лица, выполняющего роль диспетчера;
непосредственное общение по различным каналам определенной группы людей с множеством потенциальных клиентов.
Координация с помощью третьего лица легко поддается Описанию. В данном случае и клиенты, и машинистки получают рандеву с диспетчером, который принимает запросы на печать и распределяет работу между свободными машинистками.
task PERSONNEL_MANAGER isentry DOIT(.,.);end PERSONNEL_MANAGER; .task body PERSONNEL—MANAGER isbeginloopaccept DOIT (...) do .., end;PERSONNEL_FILE.GET (...);TYPING_POOL.DEPOSIT (...);TYPING_POOL.PICKUP (...);SECRETARY.PUT (...);ASSISTANT.DO_IT (...);end loop;end PERSONNEL-MANAGER;Рис. 3.8. Скелет Ада-программы для задачи управляющего по кадрам.task PERSONNEL_MANAGER isentry DOIT(.,.);end PERSONNEL_MANAGER; .task body PERSONNEL—MANAGER isbeginloopaccept DOIT (...) do .., end;PERSONNEL_FILE.GET (...);TYPING_POOL.DEPOSIT (...);TYPING_POOL.PICKUP (...);SECRETARY.PUT (...);ASSISTANT.DO_IT (...);end loop;end PERSONNEL-MANAGER;Рис. 3.8. Скелет Ада-программы для задачи управляющего по кадрам.task SECRETARY is entry PUT (...); entry GET (... );end SECRETARY;task body SECRETARY isbeginloopselectaccept PUT (,..) do .., end; oraccept GET (...) do ..'. end; end select;end loop;,end SECRETARY;Рис. 3.9. Скелет Ада-программы для задачи секретаря.task SECRETARY is entry PUT (...); entry GET (... );end SECRETARY;task body SECRETARY isbeginloopselectaccept PUT (,..) do .., end; oraccept GET (...) do ..'. end; end select;end loop;,end SECRETARY;Рис. 3.9. Скелет Ада-программы для задачи секретаря.
task PERSONNEL_MANAGER is
entry DOIT(.,.);
end PERSONNEL_MANAGER; .
task body PERSONNEL—MANAGER is
begin
loop
accept DOIT (...) do .., end;
PERSONNEL_FILE.GET (...);
TYPING_POOL.DEPOSIT (...);
TYPING_POOL.PICKUP (...);
SECRETARY.PUT (...);
ASSISTANT.DO_IT (...);
end loop;
end PERSONNEL-MANAGER;
Рис. 3.8. Скелет Ада-программы для задачи управляющего по кадрам.
task PERSONNEL_MANAGER is
entry DOIT(.,.);
end PERSONNEL_MANAGER; .
task body PERSONNEL—MANAGER is
begin
loop
accept DOIT (...) do .., end;
PERSONNEL_FILE.GET (...);
TYPING_POOL.DEPOSIT (...);
TYPING_POOL.PICKUP (...);
SECRETARY.PUT (...);
ASSISTANT.DO_IT (...);
end loop;
end PERSONNEL-MANAGER;
Рис. 3.8. Скелет Ада-программы для задачи управляющего по кадрам.
task SECRETARY is entry PUT (...); entry GET (... );
end SECRETARY;
task body SECRETARY is
begin
loop
select
accept PUT (,..) do .., end; or
accept GET (...) do ..'. end; end select;
end loop;,
end SECRETARY;
Рис. 3.9. Скелет Ада-программы для задачи секретаря.
task SECRETARY is entry PUT (...); entry GET (... );
end SECRETARY;
task body SECRETARY is
begin
loop
select
accept PUT (,..) do .., end; or
accept GET (...) do ..'. end; end select;
end loop;,
end SECRETARY;
Рис. 3.9. Скелет Ада-программы для задачи секретаря.
Диспетчер и машинистки рассматриваются клиентами как совокупный ресурс определенного назначения. Такой ресурс является аналогом активного пакета.
Сложнее описать прямые многоаспектные взаимодействия между клиентами машинописного бюро и машинистками. Клиент может зайти в машбюро и оповестить о своей просьбе всех машинисток. Это можно сделать по-разному: прокричать, позвонить в звонок, посмотреть, нет ли свободных машинисток, переговорить с кем-нибудь персонально и т. д. Если свободных машинисток несколько, они должны уметь договориться между собой, кто из них выполнит поступившую работу. И наоборот, они все могут предложить свои услуги, а клиент самостоятельно выберет одну из них, отклонив или проигнорировав
предложения остальных. В последнем варианте машинистки, не отвергнутые явно, должны быть уведомлены об отказе от их услуг. Если все машинистки перегружены, в очереди на обслуживание может стоять множество клиентов, и тогда необходим какой-либо метод прикрепления клиентов к машинисткам.
Ясно, что механизм рандеву в языке Ада служит хорошим образным представлением деятельности коллективов людей, которые взаимодействуют между собой попарно. Для того чтобы описать многоаспектное общение в рамках механизма рандеву, его необходимо свести к набору попарных взаимодействий. При этом координация с помощью третьего лица легко поддается описанию, но непосредственные многоаспектные взаимодействия описать трудно.
То, что в языке Ада допускаются только двусторонние взаимодействия между задачами, можно трактовать двояко: как весьма желательное применение принципа максимального упрощения или как неудобное, но обязательное ограничение.
С одной стороны, будь в языке Ада механизм, обеспечивающий рандеву с произвольным числом задач из заданной совокупности, на этом языке было бы проще описывать многосторонние непосредственные взаимодействия. Но тогда потребовался бы какой-либо метод организации очереди задач, которым необходимо предоставить этот механизм для взаимодействия с некоторым общим фондом (пулом). С другой стороны, как уже указывалось ранее, такой механизм легко смоделировать на языке Ада, объединив в один пакет задачу-диспетчер и задачи-исполнители и образовав при этом необходимый пул. Таким образом, двусторонний характер механизма рандеву, по-видимому, не накладывает никаких ограничений на свободу действий при проектировании. Подобный анализ структурных графов и вопросов организации программ для активных пакетов и пулов задач мы отложим до разд. 3.3.
Структурный граф, показанный на рис. 3.4, и скелеты программ на рис. 3.5 хотя и не в полной мере, но все же дают некоторое представление о функционировании реального уч-, реждения и о взаимодействии программных модулей Ада-про- граммы. В данном конкретном примере оставлен без внимания ряд аспектов, которые могли бы породить новые вопросы. Например, как вице-президент может в дальнейшем проверить сам или получить уведомление, что было выполнено правильное действие? Эти и подобные им вопросы приводят и в реальной жизни, и в программировании к необходимости нескольких рандеву между вице-президентом и управляющим по кадрам, а также между всеми остальными задачами на структурной
диаграмме. Отложим, однако, обсуждение этих проблем до разд. 3.3 и перейдем к более детальному исследованию механизма рандеву,
Представление механизма рандеву в языке Ада как взаимодействий между людьми
На рис. 3.10 дано образное описание рандеву простейшего типа в терминах взаимодействий между людьми. Изображенный на этом рисунке проситель выходит из своего учреждения и направляется в контору должностного лица, ведущего прием, где обнаруживает дверь его кабинета открытой. Он подает служащему бланк заявки, в которой изложены суть и «параметры» просьбы, и затем остается за дверью кабинета. Ведущий прием служащий, который в ожидании клиента работал при открытой двери, принимает бланк заявки и начинает обрабатывать его, а клиент в это время «дремлет». По окончании рандеву служащий вновь открывает дверь своего кабинета, «будит» ожидающего просителя, и тот возвращается в свое учреждение.
В жизни, разумеется, все сложнее, чем случай, представленный на рис. 3.10, и, как правило, либо служащему приходится ждать клиента, открыв дверь, либо клиент бывает вынужден ожидать начала рандеву за закрытой дверью. На рис. 3.11 проиллюстрированы обе эти ситуации; рандеву в обоих случаях происходит так же, как на рис. 3.10.
Более общий случай представлен на рис. 3.12. Несколько клиентов выстраиваются за дверью кабинета в очередь на прием в том порядке, в каком пришли, это соответствует дисциплине «первым пришел — первым обслужен» (наличие нескольких дверей свидетельствует о существовании нескольких входов). На языке Ада это означает, что на каждом входе образуется отдельная очередь, организованная по правилу «первым пришел — первым обслужен». В то время, когда служащий, ведущий прием, ждет клиентов, не все двери его кабинета могут быть открыты; при этом закрытые двери соответствуют в языке Ада закрытым (с помощью защитных блокировок)' входам.
Если с обращением к тому или иному входу не связаны никакие параметры, то бланк заявки можно представить себе просто как сигнал о том, что требуется услуга, обеспечиваемая данным входом. В общем же случае бланк заявки включает входные параметры и отрывной талон; в этом талоне оставлены пустые места, которые следует заполнить значениями возвращаемых параметров. Клиент забирает этот отрывной талон
Занят работой в 'своем кабинете"
Служащий, ведущий прием
Ждет при 'открытой двери'
Рандеву идет при "закрытой двери" кабинета служащего
Рис. 3.10. Функционирование механизма рандеву в языке Ада: простейший случай.
у служащего и после этого возвращается с окончившегося рандеву.
Сразу после завершения рандеву служащий, ведущий прием, может снова закрыть дверь своего кабинета (даже при
2ZZ2ZZzzzzzz'Служащий открывазг Дверь и обнаруживав г ожидающего в^о клиента рандеву начинается'Служащий открывазг Дверь и обнаруживав г ожидающего в^о клиента рандеву начинается
2ZZ
2ZZ
zzz
zzz
'Служащий открывазг Дверь и обнаруживав г ожидающего в^о клиента рандеву начинается
'Служащий открывазг Дверь и обнаруживав г ожидающего в^о клиента рандеву начинается
(б] Клиент ждет, пока освободится Служащий
Рис. 3.11. Несколько примеров рандеву.
наличии очереди) для завершения обработки запроса, связанного с последним рандеву, или для выполнения внутренних функций.
В случае когда дверь, нужная клиенту, закрыта (даже если служащий свободен, и другие двери открыты), клиент сталкивается со структурными задержками. Задержки по перегрузке возникают тогда, когда очередь образуется перед дверью, через которую обслуживание ведется с максимальной скоростью,
Рис. 3.12. Рандеву при наличии нескольких очередей на защищенных входах.
Скрытые задержки имеют место в том случае, когда все двери оказываются закрытыми потому, что служащий выполняет какие-либо собственные внутренние операции без введения защитных блокировок. Отметим, что внутренние операции могут потребовать от служащего посещения каких-либо других кабинетов, поэтому в случае закрытой двери его может и не быть на месте.
Итак, на посещение других кабинетов время расходуется непредсказуемым образом, а покинув свой собственный кабинет, служащий может упустить очень важные события. При прочих равных условиях любой человек обычно предпочитает такой способ взаимодействия, при котором люди приходят к нему, а не он к ним. В этом случае ему не приходится терять время на ожидание, если у него нет других дел.
Очевидно, что, если бы все задачи в системе вели себя столь «эгоистично», никаких взаимодействий между ними вообще не происходило бы. Как будет показано ниже в разд. 3.3, вопросы проектирования структуры взаимодействий задач кон^ центрируются вокруг одной проблемы — отбора задач, в которых выполняются операции, реже всего «накладывающиеся» на другие их функции. Это важно потому, что только в простейших системах направленность рандеву не имеет значения; например, если две задачи всегда взаимодействуют только друг
с другом, то не существенно, какая из них вызывает другую.
В заключение отметим, что если у кого-либо из читателей сложилось впечатление, будто механизм рандеву не позволяет вызывающим и вызываемым задачам выполнять параллельные операции во время обслуживания вызванной задачей запроса, поступившего на ее вход, это мнение ошибочно. Ограничение на параллельную работу действует только до тех пор, пока длится само рандеву, т. е. пока обрабатывается обращение к входу. Рандеву можно использовать только для передачи вызова, а последующая его обработка вызванной задачей может выполняться после окончания рандеву. Примером является рандеву вице-президента и управляющего по кадрам (см. рис. 3.6), в процессе которого осуществляется передача картотеки на обработку. Далее вице-президент имеет возможность продолжить свою собственную работу, а управляющий будет обрабатывать документы картотеки. В данном случае рандеву используется лишь для передачи запроса на обработку картотеки.
3.3. Разработка набора компонентов стандартных системных структур
Введение в проблему
Выше были рассмотрены пакеты и задачи в аспекте их неформального представления средствами языка Ада и приведено несколько примеров их использования. Перейдем теперь к их исследованию с более общих позиций, а именно представим и классифицируем различные способы конструирования фрагментов систем из этих стандартных блоков. Цель данного раздела заключается в определении стандартного набора (своего рода «конструктора») компонентов систем. Ясно, что в роли таких компонентов могут выступать самые различные типы стандартных элементов, поэтому необходимо ввести классификацию компонентов, проанализировать их свойства и выработать рекомендации относительно принципов выбора подходящих типов элементов в каждом конкретном случае. Отметим, что термин тип в данном контексте не равнозначен типу данных в языке Ада.
Поскольку основным источником проблем являются системы с параллельной структурой, мы будем рассматривать главным образом именно их и сначала введем несколько определений.
Системные компоненты различного функционального назначения могут представлять собой набор задач следующих типов: /
Подчиненный: задача взаимодействует с одной и только одной задачей (которая называется ведущей), получая от нее работу; может обращаться к соответствующей ведущей задаче для получения задания и уведомлять ее о завершении или прекращении работы; ведущая задача (руководитель) также может поручать ведомой (подчиненному) выполнение работы для других задач.
Исполнитель: задача, выполняющая служебные функции по требованию ряда задач-пользователей; никогда не вызывает другие задачи — ни автономно, ни в ответ на запрос; не содержит средств управления другими задачами; реагирует на обращения немедленно (при выполнении условия, что в каждый момент времени обслуживается только одна вызывающая задача).
Плакировщик: единственная функция этой задачи заключается в том, что она в определенных привилегированных режимах задерживает выполнение вызовов на конкретных входах.
Буфер: комбинация компонентов «планировщик» и «исполнитель»; реализует прием информационных объектов на хранение и их отбор для передачи.
Секретарь: задача, обладающая большей автономностью по сравнению с планировщиком-исполнителем (буфером); она не только выполняет сервисные функции и осуществляет планирование процессов, но и обращается к другим задачам за получением результатов их выполнения.
Агент: автономная задача, выполняющая не только функции исполнителя, планировщика и секретаря, но и собственную работу, которая состоит в автономных обращениях к другим задачам (отметим, что в организационных системах должностные лица, называемые секретарями, на самом деле, если следовать нашей терминологии, выполняют роль агентов).
Курьер: задача, осуществляющая транспортировку объектов между другими задачами; вызывает последние только для того, чтобы принять объект и переместить его по назначению, но не имеет никаких иных средств управления выполнением других задач.
Пользователи, потребители, распорядители и др.: автономные задачи, взаимодействующие с задачами других типов для реализации некоторых общесистемных функций.
Мы уже видели, что путем объединения задач в активные пакеты можно образовывать функциональные единицы аналогично тому, как в учреждениях люди по функциональному признаку объединяются в подразделения. Активные пакеты обладают многими свойствами задач, и для них можно ввести ту же классификацию по типам. Таким образом, фрагменты
систем можно компоновать не только из задач, но и из активных пакетов перечисленных выше типов.
Задачи и активные пакеты полезно разбить на классы в зависимости от направления их взаимодействий с другими задачами и активными пакетами в операциях управления и передачи данных. Такая классификация представлена на рис. 3.13.
В зависимости от направления пересылки данных модуль ((как и задача или активный пакет) может определяться как
ОтправительL) —♦—О Вызывающий
(а) В зависимости от направления(5) В зависимости от направления
пересылки данных.управляющих воздействий.
Рис. 3.13. Классификация системных модулей в зависимости от направления пересылки данных и управляющих воздействий.
отправитель или адресат (или быть одновременно и тем и другим). В соответствии с направленностью управляющих воздействий модуль можно классифицировать как вызывающий или вызываемый (либо тот и другой вместе). Например, при пересылке данных можно передать некоторое сообщение от вызывающего отправителя вызываемому адресату. Осуществив вызов в направлении, противоположном направлению пересылки данных, можно переслать сообщение от вызванного отправителя вызвавшему адресату. Иногда для обозначения модулей, которые одновременно являются и отправителями и адресатами или вызывающими и вызываемыми, удобно использовать термин посредник.
Перейдем теперь к рассмотрению некоторых базовых системных структур, включающих пакеты и задачи.
Структуры на основе пакетов коллективного пользования
В разд. 3.2 были кратко рассмотрены структуры последовательных систем, включающие пассивные пакеты. В таких системах не возникает особых технических или концептуальных затруднений, поэтому отложим их исследование до рассмотре-
ния конкретных примеров проектирования в последующих главах.
Проанализируем теперь взаимодействие нескольких задач с пассивным пакетом коллективного пользования; возникающая при этом проблема координации может быть решена так, как показано на рис. 3.14, а, где изображен пакет STACK (гл. 2). Видимые процедуры этого пакета имеют доступ к общим внутренним данным. Будет ли стек в действительности использоваться несколькими задачами или нет, не имеет значения для понимания существа развиваемых здесь идей. На рисунке приведены структурные графы и скелеты программ для его основных компонент.
Из рис. 3.14, а следует, что, если процедуры пакета обладают свойством повторной входимости и в нем нет совместно используемых внутренних данных или пакет обеспечивает только чтение таких данных, этот пакет пригоден для использования несколькими задачами, и никакая дальнейшая координация
Пассивный стековый пакет в исходном виде
package STACK is
procedure PUSH (...);
procedure POP (. . .);
end STACK;
package body STACK is
procedure PUSH L ..) is
-ВЫПОЛНЯ ET ФУН КЦИЮ PUSH, ИСПОЛЬЗУЯ ОБЩУЮ
- ПАМЯТЬ SPACE
end PUSH;
procedure POP (...) is
- ВЫПОЛНЯЕТ ФУНКЦИЮ РОР,ИСПОЛЬЗУЯ ОБЩУЮ ;
ПАМЯТЬ SPACE
end POP;
end STACK;
Исходный пассивный пакет.
Рис. 3.14. Пакеты коллективного пользования; пример организации стека.
task STACK is
entry PUSH (. . J;
entry POP (. . .); end STACK;
task body STACK is
procedure INTERNAL_PUSH is
- - ВЫПОЛНЯЕТ ФУНКЦИЮ PUSH,ИСПОЛЬЗУЯ ОБЩУЮ
ПАМЯТЬ SPACE
end INTERNAL_PUSH;
procedure INTERNAL^_POP is•
-- ВЫПОЛНЯЕТ ФУНКЦИЮ POP, ИСПОЛЬЗУЯ ОБЩУЮ
ПАМЯТЬ SPACE
end INTERNAL_POP;.
begin
loop
select.
accept PUSH (...) do INTERNAL_PUSH; end;
or
accept POP (...) do INTERNAL_POP; end;.
end select;
end loop;
end STACK;
Эквивалентная задача.
Рис. 3.14 (продолжение),
не требуется. Некоординируемое совместное использование общего пакета возможно и в случае, когда система функционирует так, что обращения различных задач к пакету никогда не накладываются друг на друга; в общем случае, однако, такой принцип ненадежен, поскольку с течением времени условия синхронизации могут изменяться. Во всех прочих случаях требуется координация в той или иной форме.
На рис. 3.14,6 иллюстрируется один из принципов координации, который заключается в замене пакета задачей-исполнителем с входами, обеспечивающими выполнение тех же функций, что и в процедурах исходного пакета.
Другой принцип, иллюстрируемый на рис. 3.14, в и 3.14, г, заключается в замене исходного пакета активным со встроен-
ной задачей-планировщиком, обеспечивающей исключение взаимных наложений.
Последний подход, отображенный на рис. 3.14,6, состоит в том, чтобы оставить исходный пакет без изменения и воспользоваться самостоятельной задачей-планировщиком для предоставления общего пакета задачам-пользователям по мере надобности.
Можно ли считать какое-либо из предложенных на рис. 3.14 решений предпочтительнее других? Решение на рис. 3.14,6 привлекательно тем, что в нем используется единственная задача-исполнитель; оно сочетает интуитивную очевидность с высокой надежностью. Решение, представленное на рис. 3.14, в, заманчиво тем, что в нем сохраняется неизменным внешний вид исходного пакета. Наконец, техническое решение, показанное
package body STACK is
task SCHEDULER is
entry SEIZE;
entry RELEASE;
end SCHEDULER;
task body SCHEDULER is separate;
procedure INTERNAL„PUSH (.,.) is
-- ВЫПОЛНЯЕТ ФУНКЦИЮ PUSH, ИСПОЛЬЗУЯ ОБЩУЮ ПАМЯТЬ SPACE end INTERNAL_PUSH;
procedure INTERNAL_POP (...) is
- - ВЫПОЛНЯЕТ ФУНКЦИЮ POP, ИСПОЛЬЗУЯ ОБЩУЮ ПАМЯТЬ SPACE end INTERNAL_POP;
procedure PUSH is.
begin
SCHEDULER.SEIZE;
INTERNAL_PUSH (.. J;
SCHEDULER.RELEASE;
end PUSH;.
procedure POP is
SCHEDULER.SEIZE;
INTERNAL_POP (..
SCHEDULER.RELEASE;
end POP;
end STACK-
(e) Эквивалентный активный пакет»
Рис. 3.14 (продолжение).
separate (STACK) • / task body SCHEDULER is x
' BUSY : boolean := FALSE;
begin
loop
select
when not BUSY ->accept SEIZE ;
do busy i= TRUE; end;
or
accept RELEASE , -
do BUSY ;= FALSE; endr end select;
end loop;
end SCHEDULER;
(г) Задача-планировщик ,,
Задача-планировщик
. (d) Исходный пакет оставлен без изменения — потребители k синхронизируют работу сами, используя задачу-планировщик»
Рис. 3.14 (продолжение).
на рис. 3.14, д, предоставляет задачам-пользователям излишне сложный интерфейс и, кроме того, потенциально ненадежно, так как не содержит средств прямой защиты содержимого пакета от использования задачами, которым не разрешен доступ к этому пакету.
Структуры с односторонним взаимодействием
Поскольку во всех последующих главах излагаемая методика проектирования основывается на исследовании информационных потоков, то и в данной главе разработка адекватной
структуры стандартных элементов систем имеет ту же ориентацию.
Рассмотрим, каким образом задачи могут передавать друг другу сообщения (запросы или данные) в одном направлении. На рис. 3.4 было представлено несколько примеров непосредственных взаимодействий такого рода. При этом данные могут передаваться как в направлении, определяемом рандеву, так и в противоположном. Например, на рис. 3.4 запрос от вице-президента управляющему по кадрам передается в том же на* правлении, в котором инициируется рандеву, а сообщение секретаря этому управляющему — в противоположном направлении.
В подразд. 3.2.3 была приведена классификация задержек. Анализируя в этой главе рабочие характеристики различных вариантов структур взаимодействий, «претендующих» на включение в состав «деталей конструктора», мы будем в основном принимать в расчет лишь структурные задержки, т. е. запаздывания, вызванные условным ожиданием.
Структурные задержки обладают одним очень интересным свойством: их средняя продолжительность увеличивается при уменьшении интенсивности взаимодействий и наоборот (интенсивность взаимодействий характеризует частоту пересылки ин- формацонных объектов между парами задач). Например, если некоторая задача ждет поступления сообщения, среднее время ее ожидания обратно пропорционально частоте передачи сообщений. Таким образом, высокая интенсивность взаимодействий может свести структурные задержки практически к нулю. Отсюда следует, что различным уровням интенсивности адекватны различные структуры взаимодействий.
Возможность возникновения задержек по перегрузке влияет на наши рассуждения в этой главе только в рамках принципа, сформулированного ранее: перегруженная задача в своих взаимодействиях с другими задачами всегда «предпочитает» быть вызываемой, а не вызывающей. Одна из причин подобного положения дел состоит в том, что обращение к другой активной задаче может привести к задержке по перегрузке. При этом, как отмечалось в подразд. 3.2.3, скрытыми задержками можно пренебречь.
Предположим теперь, что единственная задача-отправитель «хочет» что-то переслать единственной задаче-адресату (рис.З 3.15, а). Совершенно ясно, что здесь имеются две возможности: переслать сообщение путем безусловного обращения к вызываемому адресату (рис. 3.15,6), либо вызывающий адресат, обратившись к отправителю, может запросить нужное сообщение: при этом вызов носит условный характер [(рис. 3.15, в). Очевидно, что первый подход более предпочтителен
для адресата, а второй — для отправителя; чтобы сделать окончательный выбор между указанными вариантами, требуется дополнительная информация.
•Прежде всего необходима информация о характеристиках и функциях обеих задач в рамках целостной системы. Если эти задачи взаимодействуют только друг с другом, направление инициирования рандеву не играет роли. Если же задача-отправитель вступает и в другие взаимодействия (например, выполняет еще функции исполнителя, планировщика, буфера, секретаря или агента) и лишние помехи ее работе нежелательны, то более предпочтительной оказывается структура, в которой задача-адресат является одновременно инициатором вызова (рис. 3.15, s). При этом она должна быть подготовленной к тому, чтобы отсрочить выполнение своих собственных функ-
ОтправительОтправительАдресатАдресат(а) Поток информации.(а) Поток информации.
Отправитель
Отправитель
Адресат
Адресат
(а) Поток информации.
(а) Поток информации.
Вызывающий отправитель, вызываемый адресат.Вызывающий отправитель, вызываемый адресат.
Вызывающий отправитель, вызываемый адресат.
Вызывающий отправитель, вызываемый адресат.
Вызываемый отправитель, вызывающий адресат.Вызываемый отправитель, вызывающий адресат.(г) Промежуточное средство транспортировки вызова.(г) Промежуточное средство транспортировки вызова.(0) Промежуточный буфер(0) Промежуточный буфер
Вызываемый отправитель, вызывающий адресат.
Вызываемый отправитель, вызывающий адресат.
(г) Промежуточное средство транспортировки вызова.
(г) Промежуточное средство транспортировки вызова.
(0) Промежуточный буфер
(0) Промежуточный буфер
— —. ЗАДАЧА-КУРЬЕР НЕ ИМЕЕТ ВХОДОВ task TRANSPORTER is end TRANSPORTER;
— — ЗАДАЧА-КУРЬЕР РАБОТАЕТ В ЦИКЛЕ GET-PUT
task body TRANSPORTER is
begin loop.
• SENDER.GET (ITEM);УСЛОВНОЕ ОЖИДАНИЕ TARGET.PUT (ITEM); end loop; end TRANSPORTER
. У АДРЕСАТОВ И ОТПРАВИТЕЛЕЙ ОБЫЧНО БЫВАЕТ
НЕСКОЛЬКО ВХОДОВ
'В ПРОТИВНОМ СЛУЧАЕ ЗАДАЧА,-КУРЬЕР ВРЯД ЛИ НУЖНА
task SENDER is
ВХОДЫ ОБЪЕДИНЕНЫ В ЕДИНСТВЕННОМ.ОПЕРАТОРЕ
ВЫБОРОЧНОГО ОЖИДАНИЯ
entry GET (ITEM : out 1TEM_TYPE);УСЛОВНОЕ ОЖИДАНИЕ
end SENDER
task TARGET is
ВХОДЫ ОБЪЕДИНЕНЫ В ЕДИНСТВЕННОМ
■ОПЕРАТОРЕ ВЫБОРОЧНОГО ОЖИДАНИЯ
entry PUT (ITEM : in ITEM_TYPE);
end TARGET;
(e) Пример задачи-курьера.
Рис. 3.15. Стандартные конфигурации односторонних взаимодействий между парами задач.
ций до того момента, когда отправитель отреагирует на обращение к нему.
Если задача-адресат не приспособлена к этому и интенсивность взаимодействий не высока, такая структура не может считаться удовлетворительной. Однако в случае, когда задача- адресат является одновременно и вызываемой, как на рис. 3.15,6, рассмотренный принцип гарантирует минимальную длительность перерывов в ее работе, но может оказаться неприемлемым для отправителя.
Если же ни отправитель, ни адресат не допускают вмешательства в их работу, проблема может быть решена введением задачи-курьера, как показано на рис. 3.15, г. На этом рисунке изображены задачи с несколькими входами, так как данная структура взаимодействий подходит именно для таких задач. Вход, который вызывается задачей-курьером, можно
включить в единственный оператор приема, принадлежащий вызываемой задаче.
Задачу-курьер можно рассматривать как вспомогательную для задачи-адресата или как «партнера», который реализует за нее функции ожидания.
Поскольку задача-курьер сама вызывает и адресата и отправителя, а не они обращаются к ней, это обеспечивает минимум помех их работе; что же касается задачи-курьера, то у нее по определению нет никаких иных функций, и поэтому она может «позволить» себе простои. Такое же решение в аналогичной ситуации часто принимают и в организационных системах.
Если интенсивность взаимодействий высока, задача-курьер, иллюстрируемая на рис. 3.15, г, почти никогда не будет простаивать в ожидании нужных ей информационных объектов. В данном случае допустимо снять защитные блокировки и организовать работу задачи-курьера по фиксированному расписанию. Этого можно достичь, введя задержку на каждой итерации бесконечного циклического процесса. Отметим также, что при высокой интенсивности взаимодействий отправителю может потребоваться буфер для хранения объектов, генерируемых с большей частотой, чем та, с которой их способна принимать задача-курьер. В данном случае эту задачу можно спроектировать таким образом, чтобы она транспортировала сразу несколько объектов.
На рис. 3.15, д представлено альтернативное решение для высоких уровней интенсивности взаимодействий. Между отправителем и адресатом помещается буферизующая задача, которая может временно хранить избыточные объекты, порождаемые отправителем; в результате отпадает необходимость в собственной буферной памяти задачи-отправителя. Подобное решение приемлемо в том случае, когда задача-адресат взаимодействует с другими задачами только при посредничестве буферизующей задачи. Эту проблему мы еще обсудим ниже. Пример Ада-про- граммы для буферизующей задачи был приведен в гл. 2.
На рис. 3.15, е представлен скелет Ада-программы, иллюстрирующий типичные взаимодействия между отправителем и адресатом при посредничестве задачи-курьера. Обратите внимание, что входы, вызываемые этой задачей, и у отправителя, и у адресата включены в оператор выборочного ожидания.
А что происходит, если сообщения передают несколько задач, как показано на рис. 3.16, а? Как и прежде, здесь возможны два варианта непосредственных взаимодействий: адресат может быть инициатором вызова (рис. 3.16,6) или вызываемым (рис. 3.16, в). Однако по сравнению с рис. 3.15 здесь заметно явное отличие даже при отсутствии какой-либо допол-
нительной информации о функциях задач в рамках системы. Если задача-адресат играет роль вызывающей, именно она должна определить, какую из задач-отправителей следует вызвать, но после того как выбор сделан, остается связанной с ней до тех пор, пока вызванная задача не передаст ей что-нибудь; между тем, если задача-адресат не находится в состоянии ожидания, она может принять очередное готовое сообщение от какой-либо другой задачи-отправителя.
Если же задача-адресат является вызываемой, она способна принять первый же поступивший вызов от любого отправителя, как показано на рис. 3.16, s, и в данном случае ей нет необходимости знать их всех. Следовательно, в подобной ситуации, по-видимому, разумно делать задачу-адресат вызываемой при том условии, что задачам-отправителям не придется неоправданно долго пребывать в состоянии ожидания по причине занятости адресата другой работой.
Допустим, что задача-адресат соответственно этой рекомендации сделана вызываемой. Тогда, если она загружена собственной работой настолько, что не всегда может оперативно обслуживать обращения к ее входам, все задачи-отправители окажутся без нужды заблокированными в ожидании необходимого им рандеву. В этих условиях ни один из принципов, иллюстрируемых на рис. 3.16,6 и 3.16,s, не дает удовлетворительных результатов.
Рассмотрим теперь случай, представленный на рис. 3.16, г, когда один отправитель посылает сообщение нескольким адресатам. Если при этом задачи-адресаты являются вызываемыми, то возникают проблемы, аналогичные проиллюстрированным на рис. 3.16,6. В этом случае задачи-адресаты лучше сделать вызывающими, а задачу-отправитель — вызываемой (см. рис. 3.16, в). Каждому адресату должен соответствовать свой вход задачи-отправителя с тем, чтобы последняя могла осуществлять защитную блокировку тех входов, для которых пет сообщений, готовых для передачи. В этом методе предполагается, что задача-адресат может позволить себе простои во входной очереди отправителя. Если же это не так, то между отправителем и каждым из адресатов следует поместить задачу- курьер, как показано на рис. 3.16, е.
Разумеется, иллюстрируемые на рис. 3.15 и 3.16 проблемы неоправданных задержек, связанных с методом отбора готовых сообщений или разблокирования задач-отправителей, могут быть решены с использованием обусловленных или временных вызовов. Однако в этом случае вызывающие задачи должны быть готовы к повторению неудавшегося вызова и вполне возможно, что им даже придется организовать последовательный опрос нескольких задач прежде, чем обращение окажется
результативным. Такое решение представляется чересчур усложненным, если принять во внимание тот факт, что в языке Ада имеется готовый механизм выборочного ожидания. Программы с повторными выполнениями вызовов и с реализацией последовательного опроса вызывающих задач наверняка будут более сложными по своей логической структуре и менее эффективными, чем программы без них.
Ну, а как быть в случае нескольких отправителей и нескольких адресатов? Решение здесь состоит в организации одной или нескольких буферизующих задач (рис. 3.17). У такой задачи на рис. 3.17,6 имеется только один вход SEND (ОТ-
(а) Потоки данных при нескольких(а) Потоки данных при несколькихотправителях и одном адресате.отправителях и одном адресате.(б) Вызываемый отправитель и вызывающий адресат, '(б) Вызываемый отправитель и вызывающий адресат, '(в) Вызывающий отправитель и вызываемый адресат.(в) Вызывающий отправитель и вызываемый адресат.
(а) Потоки данных при нескольких
(а) Потоки данных при нескольких
отправителях и одном адресате.
отправителях и одном адресате.
(б) Вызываемый отправитель и вызывающий адресат, '
(б) Вызываемый отправитель и вызывающий адресат, '
(в) Вызывающий отправитель и вызываемый адресат.
(в) Вызывающий отправитель и вызываемый адресат.
(г) Потоки данных при одном отправителе и не.- ^ольких адресатах.
(е) Аналогично случаю (д), но между источником вызова и адресатом введена задача-курьер;
Рис. 3.16. Односторонние непосредственные взаимодействия между несколькими задачами.
ПРАВКА) для всех отправителей, по одному входу RECEIVE (ПОЛУЧЕНИЕ) для каждого адресата, и она является вызываемой, а не адресатом и не посредником. Сделано это по целому ряду причин.
Прежде всего очевидно, что буферизующая задача не может быть вызывающей в силу обстоятельств, отображенных на рис. 3.16,6, где отправителей несколько. Если же наделить ее функциями посредника, действующего в направлении движения потоков информации, это приведет к нежелательным послед-
(в) Буфер и задачи-курьеры.(в) Буфер и задачи-курьеры.(г) У каждого адресата свой буфер.(г) У каждого адресата свой буфер.Рис. 3.17. Непрямые взаимодействия между несколькими отправителями и ие- сколькими адресатами с помощью буферизующей задачи.Рис. 3.17. Непрямые взаимодействия между несколькими отправителями и ие- сколькими адресатами с помощью буферизующей задачи.
(в) Буфер и задачи-курьеры.
(в) Буфер и задачи-курьеры.
(г) У каждого адресата свой буфер.
(г) У каждого адресата свой буфер.
Рис. 3.17. Непрямые взаимодействия между несколькими отправителями и ие- сколькими адресатами с помощью буферизующей задачи.
Рис. 3.17. Непрямые взаимодействия между несколькими отправителями и ие- сколькими адресатами с помощью буферизующей задачи.
ствиям: задаче-посреднику придется принимать решение о том, в какой момент следует пытаться выйти на рандеву с каждой из задач-адресатов. Однако в выбранный момент времени нужный адресат может оказаться занятым другой работой, и тогда вполне вероятна необоснованная косвенная блокировка задач- отправителей. Казалось бы, эту трудность можно обойти, организовав с помощью обусловленных или временных вызовов
последовательный опрос адресатов. Но, как уу- отмечалось, такой опрос нежелателен, и его следует избегать
Введение задачи-посредника, действующей в направлении, противоположном потоку информации, оказывается неудачным решением по тем же причинам, которые привели к отказу от статуса вызывающей задачи на рис. 3.16, б.
Отметим, что проектное решение, представленное на рис. 3.17,6, где каждому адресату ставится в соответствие свой вход, возможно только в том случае, когда все адресаты заранее известны. В противном случае может использоваться единственный вход без условий ожидания (правда, при этом вызывающим задачам, возможно, придется многократно повторять вызовы входа).
В решении, представленном на рис. 3.17,6, сделано предположение, что задачам-адресатам безразличны события, которые могут произойти за время их пребывания во входной очереди буферизующей задачи. Это предположение правомерно, если у адресата нет собственных входов.
Чтобы добиться несколько большей гибкости, можно, как показано на рис. 3.17, в, между буфером и каждым адресатом использовать задачу-курьер. Это позволит задачам-адресатам ждать обращений к другим входам, в то время как задачи- курьеры ждут пересылки сообщений буферизующей задаче. Это более общий вариант решения, представленного на рис. 3.13, г.
Решение, отображенное на рис. 3.17, г, относится к случаю с большим числом задач, чем на рис. 3.17,6, при наличии необходимых свойств модульности. Вместо единственной буферизующей задачи здесь каждому адресату соответствует своя задача-буфер. Каждая такая задача выделяет отдельный канал своему адресату. По этому каналу любая задача может передавать сообщения данной задаче-адресату. Со своей стороны, задача-адресат осуществляет по этому каналу все взаимодействия с другими задачами. Благодаря такому принципу задаче- адресату уже не приходится опасаться, что она не отреагирует на какие-либо события, происходящие во время ее пребывания во входной очереди буферизующей задачи.
За использование удобных структур, показанных на рис. 3.17,6 или г, приходится расплачиваться потерей гибкости по сравнению со схемой взаимодействий, изображенной на рис. 3.17,в, поскольку в ситуациях и 6, и г адресат должен обязательно обрабатывать сообщения в том порядке, в котором они поступают от буферизующей задачи, а в случае s задача-адресат имеет возможность установить на своих входах защитные блокировки и самостоятельно управлять порядком обработки сообщений. .
task BUFFER is
entry PUT (ITEM: in ITEM_TYPEI
entry GETC (ITEM: out ITEM_TYPE)
entry GETD (ITEM: out ITEM_TYPE)
end BUFFER,-
task body BUFFER is
begin loop select accept PUT (ITEM: in ITEM_TYPE) do ЗАПОМНИТЬ СООБЩЕНИЯ СНЯТЬ ЗАЩИТНУЮ БЛОКИРОВКУ С СООТВЕТСТВУЮЩЕГО ВХОДА АДРЕСАТА ' end;1
or
when SQMETHING_FOR_TARGET_C в > accept GETC (ITEM: out ITEM—TYPE) do ПЕРЕДАТЬ ОДНО СООБЩЕНИЕ УСТАНОВИТЬ ЗАЩИТУ,ЕСЛИ СООБЩЕНИЙ БОЛЬШЕ НЕТ end;■
or
when SOMETHING_FOR_TARGET_D = > accept GETD (ITEM: out ITEM_TYPE) do
- ПЕРЕДАТЬ ОДНО СООБЩЕНИЕ ’
.УСТАНОВИТЬ ЗАЩИТУ. ЕСЛИ СООБЩЕНИЙ БОЛЬШЕ НЕТ end;'
end select;
end loop;
•end BUFFER;
Рис. 3.18. Программа задачи-буфера.
: Потерю гибкости можно было бы компенсировать за счет еще одного усложнения, состоящего в том, чтобы добавить в задачу-буфер соответствующие входы и использовать механизм выборочного ожидания. Однако при этом сильно усложняется логика взаимодействий между буфером и адресатом, так как прикладные функции оказываются распределенными между ними.
На рис. 3.18 приведен скелет Ада-программы для буферизующей задачи, изображенной на рис. 3.17,6.■
Нестандартное планирование процессов
Часто возникает необходимость обслуживания запросов не в той очередности, в которой они поступали на входы. Такую дисциплину обслуживания можно назвать нестандартным пла^
нированием. Потребность в нем может появиться из-за того, что некоторые запросы в разное время обрабатываются по- разному вследствие изменения условий или потому, что некоторые запросы имеют более высокий фиксированный приоритет по сравнению с остальными. В языке Ада нестандартное планирование наилучшим образом реализуется путем закрепления за каждым запросом, требующим особой обработки, отдельного входа. Это позволяет вызываемой задаче «в одиночку» осуществлять нестандартное планирование с использованием механизма защитных блокировок. Входы в разные моменты времени обрабатываются по-разному соответственно изменяющимся условиям. Имя каждого входа должно содержать всю информацию, необходимую обуслуживающей задаче для принятия решения о том, какие из входов следует временно закрыть. Такой принцип в некоторых случаях может потребовать определения большого количества входов. Для этой цели можно использовать таблицы входов, которые в языке Ада называются семействами входов.
Нестандартное планирование может основываться также на параметрическом описании входов. Однако это требует согласования взаимодействий между задачами. Вызывающая задача должна быть готова к тому, что ее запрос будет отклонен, если его невозможно обслужить в момент вызова входа. Это объясняется тем, что механизм рандеву в языке Ада не позволяет анализировать параметры вызова входа до выполнения оператора приема и что отсутствует явный механизм блокирования вызывающей задачи в этот момент. Неявное блокирование можно осуществить с помощью вложенных операторов приема, однако такой метод не устраняет трудностей нестандартного планирования, поскольку вложенные рандеву можно завершать только в порядке, обратном их инициализации. Следовательно, если параметры таковы, что поступивший запрос нельзя обслужить немедленно, у вызываемой задачи есть единственная возможность: завершить рандеву передачей параметра, указывающего на то, что запрос отклонен. В этом случае вызывающая задача должна быть готова к повторному выполнению обращения, а чтобы обслуживание повторных вызовов было «справедливым», у вызываемой задачи должны быть один или несколько специальных входов, обслуживаемых в первую очередь. Однако, если нельзя обойтись без дополнительных входов, почему бы вместо того чтобы пересылать параметры, не выделить каждому запросу, требующему особой обработки, отдельный вход? На самом деле это и есть наиболее рациональный принцип.
На рис. 3.19 представлена обслуживающая задача, в которой некоторым входам приписан более высокий фиксированный
- - ОБСЛУЖИВАЮЩИЙ МОДУЛЬ С ФИКСИРОВАННЫМИ ПРИОРИТЕТАМИ type LEVEL = (HIGH, MEDIUM, LOW);‘
task SERVER is
entry REQUEST (LEVEL);
end SERVER;
task body SERVER is begin loop select
accept REQUEST (HIGH) do ... end; or
when REQUEST (HIGH)'COUNT=0=> accept REQUEST (MEDIUM) do .,. end; or"
when REQUEST (HIGH)'COUNT=0 and REQUEST (MEDIUM)'COUNT=O=> accept REQUEST (LOW) do ... end;
end select;
end loop;
end SERVER;
Рис. 3.19. Задача приоритетного обслуживания (по Вегнеру).
приоритет. Этот рисунок иллюстрирует систему обозначений на структурной схеме для случая комбинированного использования фиксированного порядка и выборочного обслуживания запросов. Эти обозначения не были введены раньше по той простой причине, что для них не существует прямого аналога в языке Ада; данный механизм взаимодействий реализуется программно, как показано на рисунке. Обслуживающая задача всегда готова принять вызов входа с наивысшим приоритетом. Что же касается входов с более низким приоритетом, то они бывают открыты только в том случае, когда ни одна задача не стоит в очереди на входе, имеющем более высокий приоритет. Если очереди нет ни на одном из входов, то любой вызов входа принимается независимо от уровня его приоритета. Таким образом, задачи, которые обращаются -к низкоприоритетным входам, испытывают более длительные задержки по перегрузке.
Описанный принцип предполагает, что вызывающие задачи не осуществляют временных вызовов. В противном случае по-
требовалось бы введение каких-либо задержек для предотвращения тупиковой ситуации, которая может возникнуть в том случае, когда вызывающая задача с наивысшим приоритетом отключилась по истечении фиксированного времени ожидания, а ее обращение так и не было воспринято.
При использовании средств языка Ада на практике неизбежна одна мелкая неприятность: если в момент, когда все входы открыты, поступит «одновременно» несколько вызовов, то механизм отбора случайным образом воспримет только один из них. Последствия такого аномального поведения будут почти незаметны, если временное «окно», в котором возможно одновременное обращение нескольких задач, невелико. Однако в любом случае вне рамок установленной дисциплины обслуживания окажется всего один вызов, после чего защитные блокировки (предохранители) сработают правильно. Более приоритетный вызов в одном случае может попасть в это «окно» и не быть принят, а в другом случае — поступить несколько позже и ждать окончания обслуживания вызова с меньшим приоритетом. Разница между этими двумя случаями пренебрежимо мала.
Необходимость в подобном механизме приоритетного обслуживания может возникнуть, например, тогда, когда одновременно существуют и низкоприоритетные фоновые задачи, и высокоприоритетные задачи реального времени.
Структуры двусторонних и многосторонних ■ взаимодействий
Двусторонние взаимодействия между задачами осуществляются в том случае, когда сообщения могут передаваться в двух направлениях.
Вырожденный случай двустороннего взаимодействия имеет место тогда, когда обмен сообщениями происходит в течение одного рандеву. Это случай по сути сводится к одностороннему взаимодействию и в дальнейшем не рассматривается.
Многие механизмы, состоящие из нескольких рандеву и (или) нескольких задач, можно свести к двусторонним взаимодействиям между парами задач. Как будет видно из дальнейшего, для различных целей требуются разные варианты такого упрощения, однако некоторые из них можно сразу же отбросить как неприемлемые, поскольку они могут приводить к тупиковым ситуациям (рис. 3.20). Тупиковая ситуация может возникнуть из-за наличия прямого (рис. 3.20, а) или косвенного (рис. 3.20, б) цикла на структурном графе. Но это событие может произойти и в том случае, когда на структурном графе нет явных циклов: например, вследствие неправильной защиты
Обозначения:
(а) Непосредственный цикл на структурном графе.(а) Непосредственный цикл на структурном графе.• 1 * ожидание приема• 1 * ожидание приемаожидание вызоваожидание вызова—1^-_ выполнение оператора—1^-_ выполнение оператораприема или вызоваприема или вызоваПример для случая (а)Пример для случая (а)(б) Непрямой цикл на структурном графе.(б) Непрямой цикл на структурном графе.Пример для случая (ЯПример для случая (ЯРис, 3.20. Тупиковые ситуации при выполнении рандеву.Рис, 3.20. Тупиковые ситуации при выполнении рандеву.
(а) Непосредственный цикл на структурном графе.
(а) Непосредственный цикл на структурном графе.
• 1 * ожидание приема
• 1 * ожидание приема
ожидание вызова
ожидание вызова
—1^-_ выполнение оператора
—1^-_ выполнение оператора
приема или вызова
приема или вызова
Пример для случая (а)
Пример для случая (а)
(б) Непрямой цикл на структурном графе.
(б) Непрямой цикл на структурном графе.
Пример для случая (Я
Пример для случая (Я
Рис, 3.20. Тупиковые ситуации при выполнении рандеву.
Рис, 3.20. Тупиковые ситуации при выполнении рандеву.
одного из входов возможен цикл взаимного ожидания (рис. 3.20, в). Временные диаграммы, показывающие, как в каждом из этих случаев возникает тупиковая ситуация, приведены на рис. 3.20, г.
На рис. 3.21 показано несколько вариантов организации беступиковых двусторонних взаимодействий. Из этого рисунка видно, что непосредственные циклы на структурном графе безопасны, если все операторы приема и вызова в каждой из задач упорядочены (рис. 3.21, а). При этом одна из задач должна первой осуществлять вызов, а вторая — прием; таким образом, операторы вызова и приема в каждой из задач будут че-
(г) Задача-курьер, действующая в одном направлении,
^ Две задачи-курьеры, по одной на каждое направление»
* (Н Одна задача-курьер, общая для двух направлений
(м) Единственная буферизующая задача
(з) Индивидуальная буферизующая задача для каждого адресата.
Рис. 3.21. Структуры двусторонних взаимодействий.
редоваться. Этот подход накладывает, однако, слишком жесткие ограничения.
Другой метод предотвращения непосредственного цикла на структурном графе состоит в использовании однонаправленного условного вызова входа. Такой метод достаточно прост, но требует дополнительных логических ветвей, обеспечивающих принятие решений о том, что делать, если вызов не состоялся, и как часто следует повторять вызовы. Система в целом тоже концептуально усложняется, поскольку возврат из рандеву еще не означает, что конкретная работа выполнена. Кроме того, в
этом методе используется особая возможность языка Ада — условный вызов входа; существуют, однако, другие достаточно хорошие методы предотвращения тупиков, не требующие принятия этой крайней меры. В соответствии с кисс-принципом при желании использовать язык Ада для проектирования систем вполне естественно стремление к поиску каких-то других решений, которые могут оказаться более предпочтительными.
На рис. 3.21, в отдельные рандеву одного направления используются для передачи данных в противоположных направлениях. Сбор сообщений в данном случае может осуществляться путем организации последовательного опроса или условного ожидания, однако ни один из этих методов, вообще говоря, не дает удовлетворительных результатов.
В варианте, представленном на рис. 3.21, г, предусматривается рандеву в обоих направлениях, а во избежание тупиковой ситуации в одном из направлений используется задача- курьер. Отправитель осуществляет прием вызовов от этой вспомогательной задачи в конкретном направлении только тогда, когда у него есть сообщение для передачи. В противоположном направлении отправитель обращается ко второй задаче непосредственно. Такое решение приемлемо, если только непосредственное взаимодействие между двумя основными задачами не приводит к нежелательным помехам работе вызывающей задачи. Следовательно, вызов не должен включать условное ожидание. Преимущество данного подхода по сравнению с рассматриваемым ниже заключается в использовании меньшего количества задач, а недостаток в том, что он дает «асимметричное» решение «симметричной» проблемы.
На рис. 3.21, д для развязки тупиковых ситуаций используются две задачи-курьеры, по одной в каждом направлении; обе они находятся в состоянии условного ожидания сообщений для передачи. Такое решение оказывается более гибким, поскольку не накладывает никаких ограничений на основные задачи в отношении их взаимодействий с другими задачами; кроме того, вспомогательные задачи-курьеры позволяют, как всегда, минимизировать помехи работе обслуживаемых ими основных задач.
На рис. 3.21, е имитируется механизм взаимодействий, часто встречающийся в организационных системах, когда передача сообщений ведется пакетами, поскольку немедленная их доставка не требуется, а стоимость передачи играет существенную роль. В данном случае единственная задача-курьер собирает и передает пакеты сообщений в обоих направлениях по фиксированному графику без введения условного ожидания. Если интенсивность взаимодействий в обоих направлениях высока, одна такая вспомогательная задача, обслуживающая оба
направления по установленному расписанию, обеспечивает такой же эффект, как и две задачи (по одной на каждое направление), работающие по одинаковому графику. Сомнительно, однако, чтобы в машинных программах могли возникнуть ограничения, которые приводили бы к необходимости пакетной передачи сообщений.
Организация взаимодействий с использованием задач-курьеров ведет к большей гибкости, но при некоторых обстоятельствах имеет два дефекта:
количество требуемых задач-курьеров пропорционально числу взаимодействующих пар, а оно может быть довольно велико, если каждая задача контактирует с множеством других;
если интенсивность взаимодействий высока, задаче-отправителю или задаче-адресату может понадобиться буфер.
Чтобы избавиться от этих дефектов (как в случае двусторонних, так и односторонних взаимодействий), можно прибегнуть к буферизующей задаче, описанной в подразд. 3.3.4, немного проигрывая при этом в гибкости. Рис. 3.21, г и 3.21, з иллюстрируют методы, аналогичные соответствующим методам для односторонних взаимодействий, за тем исключением, что вступающие во взаимодействие задачи могут быть как отправителями, так и адресатами. Связанная с этим проблема утраты необходимой гибкости уже обсуждалась в подразд. 3.3.4.
Что касается соображений эффективности, то в обоих методах (с буфером и с задачей-курьером) для передачи данных между парой исходных задач требуется одинаковое количество рандеву. Однако впечатление об одинаковой эффективности несколько обманчиво, поскольку иногда при использовании метода с задачей-курьером происходит больше переключений с одной задачи на другую по той простой причине, что задач больше. Структуры многосторонних взаимодействий между большим числом задач можно соответствующим образом компоновать из структур попарных взаимодействий, приведенных на рис. 3.21.
Следует избегать произвольного установления различных структур взаимодействий для одного и того же набора задач. Такие неоднородные комбинации могут содержать скрытые тупиковые ситуации как следствие недопустимых сочетаний обращений к входам и защитных блокировок, даже если структурный граф не содержит циклов. Пример такого тупика уже был приведен на рис. 3.20, в. Читателю предлагается в качестве упражнения показать, что наличие различных структур взаимо-
действий для конкретных наборов задач может приводить к тупиковым ситуациям, связанным с зацикливанием в состоянии ожидания.
Управление потоками данных между задачами
Мы теперь знаем, каким образом одни задачи передают сообщения другим и сами ждут от них сообщений в условиях использования разнообразных стандартных структур взаимодействий. Попутно нам удалось установить, что задача-отправитель может иногда оказаться заблокированной из-за нехватки места в памяти для передаваемого сообщения. Впервые мы встретились с возможностью такой ситуации в первом примере организации прохождения задач в гл. 2 при рассмотрении буферизующей задачи; там блокировка осуществлялась путем защиты входа WRITE. Подобная защита — это один из способов, используемых задачей-адресатом для управления входящим потоком сообщений. Однако возможны и другие способы, которые описываются ниже.
Вызывающие задачи-адресаты управляют входящим потоком очень просто: они не обращаются за получением сообщений; что же касается вызываемых задач-адресатов, то они сталкиваются с более сложными проблемами.
В общем случае вызываемый адресат имеет следующие возможности управления:
заблокировать пересылаемый объект путем установки предохранителя на входе задачи-отправителя;
заблокировать пересылаемый объект в процессе рандеву, не приняв его, но освободив задачу-отправитель от ожидания;
отбросить пересылаемый объект уже в ходе рандеву;
осуществить вызов потенциальных отправителей с целью уведомления их о том, что установлен контроль над входящим потоком сообщений;
заблаговременно выдать отправителям разрешение (предоставить «кредит») на передачу сообщений.
В трех первых методах предполагается, что отправитель должен сначала попытаться передать сообщения, а затем, если потоки информации контролируются, быть готовым к ожиданию или отказу в приеме; при этом его ресурсы расходуются нерационально, и часть информации может теряться.
Четвертый метод также нельзя считать подходящим потому, что уведомление может не прийти вовремя, и, кроме того, одновременные обращения задач могут привести к тупиковой ситуации.
Пятый метод, предполагающий заблаговременную выдачу разрешения, имеет некоторые преимущества, поскольку при та-
кой организации взаимодействий отправителю гарантировано, что пересылаемые им сообщения не будут заблокированы, а адресату—что поступающие сообщения всегда можно будет принять. В простейшей форме разрешение реализуется посредством счетчика, показывающего, сколько сообщений может в данный момент принять адресат. При этом отправитель не должен превышать выданный ему «текущий кредит». Если же кредитный лимит исчерпан, отправитель должен ждать предоставления ему дополнительного кредита и только после этого сможет продолжать пересылку сообщений.
Как же необходимо организовать взаимодействия между отправителем и адресатом, чтобы кредитный лимит использовался эффективно? Это определяется выбором подходящей стандартной структуры межзадачных взаимодействий, ряд вариантов которой отображен на рис. 3.22.
Если взаимодействия осуществляются непосредственно или через задачу-курьер, то можно использовать подходы, иллюстрируемые на рис. 3.22, а—б, где предполагается, что пока кредитный лимит не исчерпан, он передается в качестве выходного параметра входа SEND (ОТПРАВКА) (начальное значение кредита можно получить, обратившись к входу SEND и передав некоторое нулевое фиктивное сообщение). Различие этих двух подходов заключается лишь в разных способах получения дополнительного кредита после того, как полученный через вход SEND кредитный лимит будет исчерпан.
После предоставления кредита адресат может сам вызвать отправителя (рис. 3.22, а); при этом тупиковой ситуации не будет благодаря фиксированному порядку чередования операторов вызова и приема. Однако возникнет чересчур тесная (и, следовательно, нарушающая принцип модульности) завязка отправителя и адресата.
На рис. 3.22, б отображен случай, когда адресат может иметь отдельный защищенный вход ASK-CREDIT (ЗАПРОС КРЕДИТА), через который отправитель может ждать получения дополнительного кредита после отправки некоторого сообщения по исчерпании кредитного лимита. Если же отправитель не может находиться в состоянии ожидания, для этой цели возможно введение задачи-курьера.
При организации взаимодействий на основе использования буферизующих задач больше всего подходит структура, показанная на рис. 3.22,в, где входы PUT могут обслуживать сразу нескольких отправителей, а каждый вход GET — ровно одну задачу-адресат, которая является владельцем данной буферизующей задачи. Каждый отправитель может одновременно быть и адресатом. х
(6) Отдельный вход ASK. CREDIT в задаче-адресате .
СообщениеСообщениеКредитКредит(в. Предоставление кредита через буферизующие задачи.(в. Предоставление кредита через буферизующие задачи.Рис. 3.22. Структуры межзадачных взаимодействий при управлении потоками информации путем выделения кредитных лимитов.Рис. 3.22. Структуры межзадачных взаимодействий при управлении потоками информации путем выделения кредитных лимитов.
Сообщение
Сообщение
Кредит
Кредит
(в. Предоставление кредита через буферизующие задачи.
(в. Предоставление кредита через буферизующие задачи.
Рис. 3.22. Структуры межзадачных взаимодействий при управлении потоками информации путем выделения кредитных лимитов.
Рис. 3.22. Структуры межзадачных взаимодействий при управлении потоками информации путем выделения кредитных лимитов.
Наборы задач, объединенные в пакет: активные пакеты
Как уже упоминалось при рассмотрении работы обычного учреждения в качестве аналога процедур параллельного программирования, часто бывает желательно трактовать совокупность задач, обслуживающих некоторые другие задачи, как активный пакет, выполняющий сервисные функции. Подобные активные пакеты могут быть тех же типов, что и задачи, т. е. могут выполнять роль подчиненных, исполнителей, секретарей, агентов, курьеров и т. п. (см. подразд. 3.3.1). Однако, как будет видно из дальнейшего, они выполняют и некоторые новые функции, например могут играть роль бюро обслуживания.
Методы использования активных пакетов можно без излишних подробностей проиллюстрировать на простом примере, взятом из жизни. Рассмотрим очередь клиентов, ожидающих обслуживания каким-нибудь кассиром в банке. Стандартное
решение проблемы состоит в том, чтобы организовать одну общую очередь и распределять затем клиентов между конкретными окошками. Здесь будет описан один частный метод, при котором клиенты стоят в очереди к окошку диспетчера, а тот сообщает им фамилию (номер окошка) свободного кассира. Клиент переходит затем к назначенному ему окошку и получает от кассира требуемую услугу.
В данном случае диспетчер управляет единственной очередью клиентов. Каждый кассир информирует его о том, что он свободен, и сообщает номер своего окошка для передачи его клиенту Клиенты ожидают, пока им сообщат номер окошка, и переходят затем к соответствующему окошку за получением услуг.
Рассмотренный пример упрощенно представлен на рис. 3.23 в форме структурных графов с использованием терминов языка Ада, причем более сложные элементы организации прохождения задач на рисунке не отображены (это будет сделано в гл. 5). На рис. 3.23,0! и 3.23,6 задачи и пакет банковских услуг представлены в форме структурного графа. Клиент, диспетчер и кассиры — это задачи, а банк—активный пакет, предоставляющий клиентам услуги, реализуемые с помощью процедур. Диспетчер выполняет функции планировщика, а кассиры — функции подчиненных, которых их начальник (диспетчер) назначает на выполнение работы для клиентов. Предполагается, что для этого они взаимодействуют с другими задачами, решаемыми в банке, но не показанными на рисунке; если это не так, то нет никакой необходимости уподоблять кассиров задачам.
Очередь на входе WAIT (ОЖИДАНИЕ), принадлежащем диспетчеру (рис. 3.23,6), является очередью для клиентов. Задача-диспетчер принимает обращение к входу WAIT только после рандеву со свободным кассиром, вызвавшим вход READY (ГОТОВ). Таким образом он организует цикл, принимая поочередно обращения к входам READ и WAIT и назначая на каждом цикле одному клиенту по одному кассиру. Кассиры работают в своем цикле, поочередно вызывая вход READY и принимая обращение к входу ASK (ЗАПРОС). Каждый кассир знает номер своего окошка и сообщает его диспетчеру, как только освобождается. Предполагается, что каждый клиент, получив номер окошка, немедленно вызывает вход ASK, принадлежащий соответствующему кассиру, посредством процедуры REQUEST-SERVICE (ОТСЛУЖИВАНИЕ-ЗАПРОСА). Если он этого не сделает, то произойдет ошибка, в результате которой кассир окажется заблокированным.
Таким образом, клиенту, вызвавшему процедуру REQUEST-TELLER (ЗАПРОС-КАССИРА), может быть придется
ожидать возврата из процедуры WAIT. Возможно, самому диспетчеру тоже придется ждать обращения к входам WAIT или READY. Кассир может ожидать возврата из процедуры READY, а затем ждать обращения к входу ASK.
На рис. 3.24 приведен скелет Ада-программы, соответствующей построенным структурным графам. Заметьте еще раз, насколько полно структурный граф помогает выработать концептуальное представление принципов организации и функционирования программы. Для этого скелет программы на самом деле совсем не нужен. Обсуждение решений в ходе проектирования можно вести исключительно в терминах структурного графа. Программа необходима только для того, чтобы определить некоторые детали, например метод идентификации задач- кассиров, который в данном случае предельно прост: каждой такой задаче присвоен собственный номер окошка, инициализируемый до начала выполнения программы. Этот номер передается от задачи к задаче, как показано на рисунках, и используется на конечном этапе в операторе отбора для определения нужного кассира. Более совершенные способы определения и идентификации пулов задач рассматриваются в гл. 5.
Для полноты представлений на рис. 3.25 приведены опущенные подробности скелета программы. Тела задач, замененные в теле пакета BANK (БАНК) заглушками, здесь определены во всех деталях.
Хотя в данном конкретном примере взаимодействия кассиров с пакетами и задачами, внешними по отношению к их собственному пакету, не показаны, в реальной жизни они встречаются повсеместно. В общем случае активные пакеты
(а) Структурный граф, иллюстрирующий внешний вид активного банковского пакета
Рис. 3.23. Активный пакет на примере банковских операций.
могут не только быть вызываемыми, но и сами способны вызывать другие модули.
Конкретный тип активных пакетов, проиллюстрированный на этом примере, можно назвать сервисным пулом. Сервисный пул — это активный пакет, который предоставляет отдельным
package BANK is
type T_TYPE is (DEPOSIT, WITHDRAW, CHECK_ACCOUNT, PAY_BILL);
type RETYPE is ...ЗДЕСЬ ПЕРЕЧИСЛЯЮТСЯ РЕЗУЛЬТАТЫ;
type WICKET is integer range 1 .. 3;
procedure REQUEST_TELLER (NAME : out WICKET;
procedure REQUEST_SERVICE (NAME: in WICKET;
■ TRANSACTION : in T_TYPE;
RESULT: out R_TYPE);
end BANK;
package body BANK is
NAME : WICKET;
task TELLER! is
entry ASkCTRANSACTION : in T_TYPE;
RESULT : out R_TYPE);
end TELLER1;
task body TELLER! is separate;
task TELLER2 is
task TELLERS is
task DISPATCHER is
entry WAIT ( NAME : out WICKET);
entry READY ( NAME : in WICKET);
end DISPATCHER;
task body DISPATCHER is separate;
procedure REQUEST_TELLER ( NAME : out WICKET) is begin DISPATCHER.WAIT ( NAME );
end REQUEST-TELLER; ,
procedure REQUEST_SERVICE ( NAME: in WICKET;
TRANSACTION.: in T_TYPE;
RESULT: out R_TYPE);
begin
case NAME is
when 1 = > TELLER1.ASK (TRANSACTION, RESULT);
when 2 = > TELLER2.ASK (TRANSACTION, RESULT);
when 3 =- > TELLER3.ASK (TRANSACTION, RESULT); end case;
end REQUEST_SERVICE;
end BANK;
Рис. 3.24. Банковский пакет, содержащий следы задач (заглушки).
вызывающим задачам услуги одной из ряда идентичных обслуживающих задач.'
Как будет видно из последующих глав, активные пакеты можно использовать так же, как транспортное средство двупа-
—ТЕЛА ЗАДАЧ ПАКЕТА BANK
Separate (BANK )
task body DISPATCHER is
NAME: WICKET; ■ begin loop accept READY (NAME : in WICKET ); accept WAIT (NAME t out WICKET); end loop;
end DISPATCHER;
Separate (BANK)
task body TELLER1 is
NAME : WICKET : = 1;'
begin loop.
DISPATCHER.READY ( NAME );
accept ASK( TRANSACTION : in T_TYPE;
RESULT I out R TYPE)
do WORK;
end;
CLEAN_UP_AFTER_WORK; end loop;
end TELLER!
ИТ.Д. ДЛЯ ВСЕХ ОСТАЛЬНЫХ КАССИРОВ
Рис. 3.25. Тела задач из пакета BANK.
правленного действия или как универсальные подчиненные задачи или задачи-агенты всевозможных типов.
Выводы
Можно было бы продолжать и дальше исследование различных проектных решений по выбору конфигурации систем, однако на данном этапе это повлекло бы за собой излишнюю детализацию концепций. В данном разделе мы продемонстрировали методы описания структуры системы, сконструированной из стандартных Ада-блоков высокого уровня (пакетов и задач). Выбранная нами методика описания вполне доступна читателям, не обладающим специальными знаниями тонкостей языка Ада. Требуются лишь понимание содержательной стороны обозначений на структурной диаграмме и правильная оценка механизма рандеву. Пользуясь таким неформальным интуитивным представлением, функционирующую систему можно рассматривать просто как коллектив людей, сотрудничающих для достижения конечной цели, а структуру системы можно спроектировать на основе накопленных знаний о механизмах поведения коллективов в организациях.
Привлекая эту аналогию, мы ввели некоторые полезные для концептуального яроектирования систем термины «подчинен-
Ный», «исполнитель», «планировщик», «секретарь», «агент», «курьер», «бюро», «буфер», характеризующие различные типы задач.
Мы старались при этом по возможности не касаться вопросов эффективности различных введенных структур, которая, правда, играет особенно важную роль в многозадачных системах, где для целей транспортировки и(или) буферизации требуются задачи-посредники. Подробное обсуждение вопросов эффективности мы отложим до части Ш, в которой анализируются примеры системного проектирования.
3.4. Связь структурных графов с Ада-программами
Старая поговорка «лучше один раз увидеть, чем сто раз услышать» применительно к проектированию справедлива только в том случае, когда каждый увидевший некоторую «картинку» уверен, что при необходимости сможет описать ее сотней слов. Чтобы вселить в читателя такую уверенность, в разд. 3.3 были приведены Ада-программы для некоторых графических примеров. В подразд. 3.4.1 дано краткое ретроспективное обсуждение механизма отображения схематических, представлений программы.
В подразд. 3.4.2 и 3.4.3 поднимаются проблемы, которые на данном этапе начинающему разработчику могут показаться не существенными, но должны вызвать интерес у более искушенного читателя; при первом чтении эти разделы можно опустить. В подразд. 3.4.2 обсуждается ряд дефектов, свойственных языку Ада в части ограниченных возможностей описания в терминах Ада-модулей конкретных замыслов разработчика систем. Наконец, в подразд. 3.4.3 показано, каким образом и для чего мы неявно, но преднамеренно ограничивали в данной главе свободу проектировщика в выборе используемых средств языка Ада, далеко не полно отражающих его истинные возможности.
Отображение структурных графов в Ада-программы
В подразд. 3.3 на конкретном примере было показано, что структурные графы чисто механическим способом непосредственно отображаются в Ада-программы.
Интерфейсные гнезда блоков, соответствующих пакетам и задачам, прямо преобразуются в объявления модульных спецификаций. Имена гнезд превращаются в имена процедур или входов, имена, связанные со стрелками потоков информации,—■ в параметры. Стрелки доступа, направленные к пакетам, преобразуются в вызовы процедур, а направленные к задачам —
в вызовы входов. Все обозначения, введенные для различных способов организации рандеву, имеют прямое соответствие в языке Ада. Не обязательно, чтобы имена гнезд были уникальны, поскольку в языке Ада вызов процедуры или входа уточняется с помощью имени пакета или задачи. Тела моду* лей программируются отдельно от интерфейсов и их внутренние детали невидимы сквозь интерфейс; это подчеркивает близость пакетов и задач к понятию черного ящика. Модули с одинаковым интерфейсом, но по-разному реализованные, взаимозаменяемы.
Однако некоторые аспекты структурных графов все-таки невозможно отразить в спецификациях Ада-модулей.
Ограничения, которые язык Ада накладывает
на спецификацию структур
Язык Ада не позволяет описать все взаимосвязи структур
ного графа на уровне специфг ции модуля не требуется указывать, к каким модулям он имеет доступ и какие из них имеют доступ к нему. Поэтому компилятор в общем случае не может проверить, выполняются ли ограничения, наложенные разработчиком на взаимосвязи, и в принципе одни модули могут вызывать другие ошибочно. Единственным очевидным исключением является случай, когда модули компилируются раздельно. Тогда для указания раздельно компилируемых модулей, к которым будет организован доступ, потребуется спецификатор совместимости with. Однако подобные спецификаторы могут появиться и в теле модулей, в силу чего они не характеризуют структуру на уровне объявлений в разделе спецификаций. Более того, в спецификаторе совместимости нельзя указывать имена за-
каций. Например, в специфика-каций. Например, в специфика-package С isreguired (D, Е);is required by (A, B);procedure С 1 (..J;procedure C 2 end package C;package С isreguired (D, Е);is required by (A, B);procedure С 1 (..J;procedure C 2 end package C;Рис. 3.26. Пример спецификации пакета, выполненный с использованием символики структурных графов.Рис. 3.26. Пример спецификации пакета, выполненный с использованием символики структурных графов.дач.
каций. Например, в специфика-
каций. Например, в специфика-
package С is
reguired (D, Е);
is required by (A, B);
procedure С 1 (..J;
procedure C 2 end package C;
package С is
reguired (D, Е);
is required by (A, B);
procedure С 1 (..J;
procedure C 2 end package C;
Рис. 3.26. Пример спецификации пакета, выполненный с использованием символики структурных графов.
Рис. 3.26. Пример спецификации пакета, выполненный с использованием символики структурных графов.
Как могло бы выглядеть подобное объявление для структурного графа, показано на рис. 3.26. Структурную информа-
цию такого рода полезно включать в комментарии к разделам спецификаций пакетов или задач.
В разделе спецификаций пакетов и задач не может присутствовать какая бы то ни было семантическая информация. Такую информацию следует давать в комментариях. Это относится не только к функциям процедур и входов, но и к природе взаимодействий между задачами, включая те, которые происходят между задачами, встроенными в активный пакет. Как
package С is
—активный
необходим для А и В
.procedure С1 (.,
— выполняет функцию
“ “ условное ожидание приема вызова не более Т с
procedure С2 L ,.), :выполняет функцию ...
=—■ условного ожидания нет
end С;
Рис. 3.27. Необходимые комментарии к спецификации пакета на рис. 3.26.
показано на рис. 3.27, природа этих взаимодействий часто имеет важное значение и для вызывающих, и для вызываемых задач. Мы советуем читателю использовать подобные комментарии в разделе спецификаций задач и активных пакетов.
Рассмотренные выше ограничения языка Ада не создают помех для непосредственного преобразования структурных диаграмм в тела Ада-программ; однако из-за них возникает необходимость документировать замыслы разработчика с помощью комментариев к спецификациям.
3.4.3. Суть ограничений свободы выбора средств языка Ада
Представленные в данной главе графическая нотация и методология совсем несложны. У подготовленного читателя могут даже возникнуть возражения против такого упрощения, поскольку оно наверняка не позволит использовать все заложен-
ные в языке Ада возможности. Возражение законное, но оно не имеет отношения к делу.
Для проектирования систем средствами языка Ада имеются, конечно, и другие дополнительные возможности, которые не охватываются введенной в данной главе системой обозначений и предлагаемым методом. Однако говорить о них можно только при наличии более глубокой теоретической базы. Все представленные до сих пор варианты структур легко описать графически, они удовлетворяют широкому кругу технических требований, и их можно непосредственно отображать в Ада-про- граммы. Автор придерживается мнения, что к вариантам структур, которые невозможно просто описать графическими средствами, следует прибегать в самую последнюю очередь.
В данной главе предложена простейшая методика организации прохождения задач, в рамках которой сделано неявное предположение о том, что системы состоят из конечного числа задач, которые активизируются при запуске и затем работают в цикле бесконечно долго. Нужные функциональные возможности при таком допущении не теряются, но зато достигается значительное упрощение. Язык Ада, однако, обладает гораздо большей универсальностью; задачи в нем можно активизировать и завершать в динамическом режиме. Сложные правила завершения задач — одна из наиболее тонких отличительных особенностей организации работ в языке Ада. Отказавшись от использования возможностей динамической активизации и завершения задач, мы избавляемся от необходимости следить за выполнением этих правил и достигаем четкости концептуального представления системы. Часто на переменное число работ необходимо назначать переменное число задач; чтобы выполнить это, можно сформировать пул, содержащий фиксированное количество задач. Если какая-либо задача в таком пуле простаивает, это значит, что она ждет либо обращения к собственному входу, либо ответа на ее обращение к другой задаче. То нежелательное обстоятельство, что память при этом занята стеками и таблицами дескрипторов простаивающих задач, часто оказывается весьма небольшой платой за достигаемую простоту.
В гл. 5 будет рассмотрен более общий принцип организации прохождения задач.
В данной главе предполагалось, что пакеты и задачи снабжены одинаковым интерфейсом доступа и что к пакетам можно получить доступ только через процедуры, а к задачам —■ лишь через входы. На самом деле пакетный интерфейс в языке Ада предоставляет возможность прямого доступа практически к любому элементу пакета даже нестандартным методом, когда это необходимо. Однако, приняв единый стандартный
тип интерфейса, мы достигаем тем самым большей простоты конструкций. Мы будем всюду в дальнейшем придерживаться именно этой точки зрения.
В этой главе совсем не рассматривались исключительные ситуации, поскольку методология данной книги предполагает, что исключения следует сводить к уровню внутренних деталей модулей, а ошибки модульных сопряжений должны регулироваться с помощью параметров вызовов. Этот принцип весьма прост и вполне приемлем. В гл. 5 будет проведен более широкий анализ исключительных ситуаций.
Стрелки, изображающие потоки данных, использовались в данной главе достаточно произвольно; параметры, пересылаемые между модулями, указывались на них так, как если бы передавались их значения (т. е. конкретные значения параметров дублировались в контексте модуля-адресата). Таким способом удалось обойти проблему указателей (переменных доступа в языке Ада).
Трудность использования указателей состоит в том, что они дают ссылку на динамические объекты, которые могут оказаться перемещенными или использованными для каких-либо других целей, а некоторые программные модули все еще будут продолжать осуществлять неверные обращения к ним. Это происходит из-за того, что экземпляр указателя, хранящийся в вызывающей программе, не уничтожается при передаче его другому модулю. Если в таких условиях вызывающим модулем делается попытка использовать этот указатель уже после того как соответствующий ему объект был перемещен или использован по другому назначению, результаты могут оказаться непредсказуемыми.
К сожалению, обойтись совсем без использования указателей невозможно, поскольку в языке Ада некоторые необходимые манипуляции нельзя выполнить без них. Например, при реализации коммуникационного пакета, по-видимому, не удастся обойтись без указателей сообщений, пакетов данных и т. п. Указатели будут рассмотрены ниже, в гл. 5.
Наконец, в данной главе совершенно остались без внимания вопросы родовой принадлежности, которая, как мы считаем, гораздо теснее примыкает к проблемам реализации систем, чем к их проектированию. Поэтому в данной книге концепция рода вообще не будет рассматриваться,
3.5. Заключение
На основании материала данной главы, читатель, не знакомый с языком Ада в деталях, вполне сможет не только разобраться в составленных кем-то системных описаниях на языка
структурных диаграмм, показывающих взаимодействия между Ада-пакетами и задачами, но и сумеет сам конструировать такие структурные схемы.
В этой главе был дан также обзор целого ряда проблем системного проектирования и положено начало разработке архитектурных принципов конструирования систем из набора стандартных модулей.
Вообще язык Ада предоставляет программистам большую свободу выбора выразительных средств. Сделанные явно или подразумеваемые в данной главе предположения ограничивают свободу разработчика в процессе проектирования только в целях систематизации его процедур. Мы считаем, что язык Ада как таковой предоставляет разработчику слишком большую свободу, что может привести к созданию чрезмерно сложных или потенциально ненадежных системных структур. Поэтому некоторое ограничение этой свободы не должно принести никакого вреда и даже целесообразно для пользы дела, поскольку в этой книге мы неизменно следуем кисс-принципу.
Глава 4
Введение в проектирование архитектуры системы (с примерами)
Введение
Цель этой главы—дать описание процесса проектирования, проиллюстрировать его несколькими простыми примерами и обсудить целый ряд новых технических задач проектирования, возникающих в связи с этими примерами. Изложение основывается на материале гл. 3, а рассматриваемые примеры подкрепляют развитые в ней концепции.'
Фаза проектирования, являющаяся частью жизненного цикла системы, коротко охарактеризована в табл. 4.1. Ей предше-
Общее проектирование
— разработка интерфейса пользователя
— определение функций системы
До уровня подсистем и основных или критичных модулей в рамках основных или критичных подсистем
Для проверки интерфейса пользователя и архитектурных принципов построения системы, определенных к данному моменту
Уровень 1
С детализацией до модулей
Уровень 2
Определение внутреннего содержания каждого модуля
।— разработка архитектуры
Планирование испытаний
Рабочее проектирование
системы
Таблица 4.1. Фаза проектирования системы, выделяемая в жизненном цикле
Основные стадии и этапы
Пояснения
ствуют фазы анализа и формулирования требований, а за ней следует фаза реализации. Фаза проектирования сама по себе может быть разбита на три основные стадии: общее проектирование, разработка плана испытаний и рабочее проектирование. Основное внимание в этой главе уделяется стадии общего проектирования).
Общее проектирование связано с описанием интерфейса пользователя, определением функций системы и разработкой ее архитектуры. Разработка пользовательского интерфейса относится к фазе проектирования по той причине, что принципы организации этого интерфейса тесно связаны с архитектурой всей системы в целом. Это значит, что некоторые характеристики интерфейса пользователя могут требовать вполне определенных подходов к построению архитектуры системы и наоборот. Поэтому важно, чтобы в работах фазы проектирования принимали участие и разработчики системы, и ее будущие пользователи. В этой фазе жизненного цикла системы во всех деталях описываются ее характеристики, видимые для пользователя, в том числе все команды, их синтаксическая структура, параметры, сообщения об ошибках, процедуры запуска системы, процедуры устранения ошибок и т. п.
Этап определения функций системы необходим для правильного распределения функций между модулями системы в процессе разработки ее архитектуры. Спецификация функций системы содержит простой перечень и характеристику всех функций без какого-либо явного или подразумеваемого объединения их в группы в рамках конкретных модулей.
Этап разработки архитектуры системы, являющийся частью стадии общего проектирования, связан с выделением модулей системы, распределением функций между модулями и установлением правил взаимодействия модулей в целях организации надлежащего функционирования системы в целом.
Стадия планирования испытаний включает разработку тестовых данных, контрольных примеров, проверочных модулей, процедур тестирования и принципов организации испытаний системы. Тестирование связано с проверкой работоспособности системы в целях приобретения уверенности в том, что, во-первых, она функционирует без ошибок и, во-вторых, что она удовлетворяет сформулированным требованиям. За тестированием следует отладка, в рамках которой осуществляется поиск источников затруднений, возникающих в процессе тестирования, и их устранение. Подготовка плана испытаний является очень важной стадией фазы проектирования, поскольку в ходе его разработки может быть достигнуто более глубокое понимание реальных механизмов функционирования системы и зачастую вскрыта неадекватность интерфейса пользователя техническим требованиям к системе. Вследствие этого в реальных проектах стадии общего проектирования и планирования испытаний имеют тенденцию к взаимному перекрытию.
Заключительной стадией проектирования является разработка рабочего проекта системы, в котором детализация решений доводится до такой степени, чтобы остальная работа
Программы, записанные в микросхемах ППЗУ, расположенных на системных платах
В целевой машине нет операционной системы
Рис. 4.1. Основные элементы целевой системы для примеров гл. 4,
могла быть поручена непосредственным исполнителям. В случае крупномасштабных систем проектирование может осуществляться рекурсивно: сначала для подсистем, затем для их частей и т. д.
В данной главе мы рассмотрим методологию и технические вопросы проектирования системной архитектуры в рамках простых задач, предполагающих использование несложного вычислительного оборудования. С этой целью нами будут спроектированы три простые системы, ориентированные на применение настольных микропроцессорных вычислительных комплексов (МПВК) типа показанного на рис. 4.1. Предполагается, что в состав такой системы входят текстовый дисплей с регенерацией изображения, осуществляемой непосредственно по информации из ЗУ аппаратным способом, клавиатура для ввода команд и данных и печатающее устройство для получения выходных печатных копий. Программы и постоянные данные хранятся в кристаллах ППЗУ (программируемых постоянных запоминаю-
щих устройств), которые располагаются на съемных системных платах, вставляемых в гнезда штепсельных разъемов на монтажном шасси. В качестве оперативной памяти, многократно стираемой в процессе счета, используются кристаллы ЗУПВ (запоминающих устройств с произвольной выборкой). Такой вычислительный комплекс не имеет никакой встроенной универсальной операционной системы, поэтому разрабатываемые для него программы должны предусматривать реализацию всех функций управления МПВК, его сопряжение с другими устройствами, а также контроль и синхронизацию всех внутренних операций, связанных с вводом информации с клавиатуры и выводом ее на экран и печатающее устройство.
Этот настольный МПВК мы будем называть целевой системой, считая, что программные средства для нее разрабатываются на отдельной макетной инструментальной системе с использованием компилятора языка Ада и программатора кристаллов ППЗУ. Предполагается, что механизмы многозадачного режима, предусматриваемые в языке Ада, обеспечиваются соответствующим программным ядром, хранящимся в ППЗУ целевой системы. Подобная организация гарантирует возможность непосредственного применения Ада-программ в целевой системе.
Альтернативный подход состоит в использовании какого-либо другого языка инструментальной системы, например Паскаля или ПЛ/М, и в расширении этого языка определенной системой соглашений относительно среды программирования и соответствующим рабочим программным ядром целевой системы, обеспечивающим поддержку концепций пакетов и задач, реализуемых в языке Ада.
В качестве объектов разработки, иллюстрирующих излагаемые в книге методы, выбраны следующие три системы:
LIFE — система, реализующая ЭКОЛОГИЧЕСКУЮ ИГРУ, в которой играющие стороны используют клавиатуру и текстовый дисплей.
FORMS (ФОРМАТИРОВАННЫЙ ВВОД)- система, позволяющая оператору вводить с клавиатуры данные по форме, высвечиваемой на экране дисплея, и получать этот документ в печатном виде строка за строкой по мере заполнения высвеченного бланка.
DIALOGUE — ДИАЛОГОВАЯ СИСТЕМА, обеспечивающая операторам, расположенным в разных пунктах, возможность взаимодействия посредством пересылки сообщений, которые при передаче формируются, а при приеме отображаются на экранах их дисплеев.
Простота предполагаемой целевой системы очевидным образом ограничивает применимость этих разработок. Наиболее
существенным недостатком является отсутствие в целевой системе внешнего ЗУ, однако мы умышленно упрощаем структуру целевой системы, чтобы рассматриваемые примеры были по возможности несложными для понимания целого ряда связанных с ними общих проблем проектирования. Как будет показано далее, предлагаемые методы решения этих проблем могут быть легко распространены и на более сложные целевые системы.
В данной главе излагается методология и рассматриваются технические вопросы проектирования применительно к разработке архитектуры программного обеспечения для трех упомянутых выше простых прикладных систем. В разд. 4.2 дается обзор известных стратегий и методов проектирования, разд. 4.3 содержит сведения, касающиеся принципов неформального, прагматического подхода к процессу проектирования, а в разд. 4.4—4.6 рассматриваются конкретные примеры проектирования.
Стратегия проектирования
Применяя термин стратегия проектирования, мы имеем в виду начальные условия, общую направленность и основные принципы разработки системной архитектуры; например, одной из стратегий проектирования является нисходящая функциональная декомпозиция. Термин методология проектирования мы используем для обозначения понятия, включающего, кроме стратегии проектирования, еще и систематическую процедуру, с помощью которой проектировщик описывает, совершенствует и регистрирует свои проектные решения.
С точки зрения направления, в котором ведется разработка проекта системы, различают стратегии «сверху — вниз», «снизу— вверх», «изнутри—-к границам» и «от границ — внутрь».
В аспекте идеологических основ процесса системного проектирования выделяются стратегия функциональной декомпозиции, стратегия, ориентированная на информационные потоки, и стратегия, ориентированная на структуры данных. Эти стратегии описываются и иллюстрируются в последующих разделах.
Стратегия функционального синтеза и декомпозиции
Схема функциональной декомпозиции по принципу «сверху— вниз» показана на рис. 4.2. В рамках этой схемы система первоначально представляется в виде некоторого аморфного воображаемого объекта, который должен выполнять все функции, указанные в его функциональном описании. Этот на-
Рис. 4.2. Функциональная декомпозиция поРис. 4.2. Функциональная декомпозиция попринципу «сверху — вниз».принципу «сверху — вниз».
Рис. 4.2. Функциональная декомпозиция по
Рис. 4.2. Функциональная декомпозиция по
принципу «сверху — вниз».
принципу «сверху — вниз».
бор функций рассматривается как одна сложная функция F; нисходящая функциональная декомпозиция продолжается далее путем разложения F на подфункции, которые в свою очередь тоже разбиваются на подфункции и т. д.
Одна трудность, связанная с функциональной декомпозицией «сверху — вниз», заключается в том, что этот принцип не ведет естественным образом к получению стандартного набора функций на самом нижнем уровне иерархии. Многие системы в результате такого процесса проектирования приобретают скорее контуры алмазного кристалла с выпуклостью в средней части, чем треугольника, поставленного на основание. Между тем нередко обычные функции самых нижних уровней иерархии могут быть определены заранее.
На рис. 4.3 иллюстрируется соответствующая такой ситуации стратегия функционального синтеза по принципу «снизу —•
Шаг 3^Шаг 3^Шаг IШаг I
Шаг 3^
Шаг 3^
Шаг I
Шаг I
Рис. 4.3. Функциональный синтез по принципу «снизу—’ вверх».
Шаг 2Шаг 2
Шаг 2
Шаг 2
Рис. 4.4. Функцио^ нальный синтез и декомпозиция по принципу «изнутри — к границам».
вверх». При этой стратегии исходные функции группируются в агрегированные функции все более высокого уровня, пока не будет достигнута вершина системы, которую можно рассматривать как одну сложную функцию.
Бывает и так, что сначала оказывается легче выделить функциональные элементы, относящиеся к некоторому среднему уровню функциональной иерархии. На рис. 4.4 иллюстрируется целесообразная в этом случае стратегия функционального синтеза и декомпозиции «изнутри — к границам». Она представляет собой комбинацию двух рассмотренных ранее стратегий, являясь восходящей стратегией для синтеза «изнутри — вверх» и нисходящей стратегией для декомпозиции «изнутри — вниз».
С нисходящей функциональной декомпозицией, восходящим функциональным синтезом и их вариантами связан целый ряд серьезных проблем. Первая из них заключается в том, что обе стратегии предполагают наличие у системы какой-либо определенной вершины, где управление через некоторый интерфейс передается от системы внешнему автономному объекту. Для системы со структурой вложений свойственно быстрое увеличение числа внешних автономных объектов, таких, как человек- оператор, сеть связи, измерительные устройства и т. п., которые более логично считать связанными с «боковыми гранями», а не с ее вершиной или основанием.
Источником другой проблемы является то, что в рамках стратегий «сверху — вниз» и «снизу — вверх» не принимается во внимание никакая информация: вопросы прохождения данных, совместного их использования и построения вложенных структур оставляются для выяснения после завершения процедур функциональной декомпозиции или синтеза. Потоки информации и структура данных становятся, таким образом, категориями, подчиненными по отношению к задачам управления. Однако проектирование многих (если не большинства) систем более естественно начинать именно с рассмотрения данных.
Третья проблема, характерная для стратегий функционального синтеза и декомпозиции, заключается в том, что они сильно затрудняют установление четких критериев оценки получающихся в результате структур. Поэтому разные разработчики будут завершать эту фазу проектирования с совершенно различными результатами функциональной декомпозиции.
Стратегия проектирования, ориентированная
на структуру данных
Если при функциональной декомпозиции основное внимание сосредоточивается на структуре управляющей логики программы безотносительно к структуре ее данных, в альтернативном
подходе внимание концентрируется прежде всего на структуре данных, в соответствии с которой строится структура управляющей логики. Такой подход может быть назван ориентированным на структуру данных и, по-видимому, наиболее целесообразен при разработке систем обработки коммерческих данных, где проблемы архитектуры решаются в рамках средств операционной системы, и все, что необходимо сделать, — это произвести структурирование файлов и записей в них. В этой книге мы в основном рассматриваем вопросы проектирования систем, в которых проблемы архитектуры имеют первостепенное значение, и поэтому не будем касаться стратегий проектирования, ориентированных на структуру данных.
Стратегия структурного проектирования, ориентированного на потоки данных
’ Стратегия проектирования, о которой будет идти речь в дальнейшем, может быть названа структурным проектировани-
(а) Система.
(6) Последовательный поток данных.
Рис. 4.5. Последовательный информационный поток.
ем, ориентированным на потоки данных. В рамках этой стратегии сначала определяют ключевые компоненты потоков информации, циркулирующих в системе, а затем, идентифицируя функции преобразования в узловых точках информационного потока, производят своего рода функциональную декомпозицию; результатом таких действий является граф информационных потоков. Следующий шаг состоит в построении на его основе структурного графа, который описывает структуру управляющей логики системы для реализации нужного информационного потока. Та же стратегия применяется далее к подсистемам, подсистемам подсистем и т. д., и при этом умышленно игнорируются детали структуры данных.
На рис. 4.5 схематически отображен процесс структурного проектирования, ориентированный на информационные потоки,
для случая последовательной обработки данных в потоке. Вначале можно считать, что проектируемая система в целом должна выполнять сложную функцию F по преобразованию входных данных в выходные, как показано на рис. 4.5, а. Затем необходимо определить внутренние компоненты потока данных и построить информационный потоковый граф, детализирующий эти внутренние потоки данных (рис. 4.5, б).
Функциональные элементы Fl, F2 и F3 являются блоками преобразования, характер которых на данном этапе не раскрывается. Нежесткость назначения этих функциональных блоков на информационном потоковом графе подчеркивается их условным представлением в форме облачка, как это делалось ранее на рис. 3.1. Узлы графов информационных потоков иногда еще изображают в виде кружков; в этом случае их называют пузырьковыми диаграммами. В дальнейшем мы будем называть узлы информационных потоковых графов модулями.
Информационный потоковый граф (ИПГ) в минимальной степени определяет характер как информационных связей, отображаемых стрелками, так и модулей, соответствующих узлам. Например, стрелками могут представляться прикладные данные, управляющая информация типа запросов, сообщений, ответов, квитирующих сигналов и т. п. Они могут соответствовать обращениям по значению или по ссылке, считыванию с разрушением или без разрушения информации. Для каждого из этих видов связи не вводится никаких специальных символов, но если на данном этапе проектирования это различие важно, соответствующие особенности должны быть разъяснены в документации, описывающей граф. В противном случае подобную конкретизацию можно отложить до более поздних этапов проектирования.
Модулями в графе, представленном на рис. 4.5, б, могут быть пакеты, задачи, процедуры, функции либо обособленные информационные объекты. Модули сами могут обеспечивать необходимое управление потоком данных или может требоваться внешний по отношению к этим первичным модулям вспомогательный блок управления. Для указания характера управляющих взаимодействий между модулями может потребоваться введение в информационный потоковый граф дополнительных компонент; этот случай иллюстрируется на рис. 4.6—4.10.
На первом из этих рисунков демонстрируется наиболее прямой путь преобразования ИПГ в структурный граф. При этом методе ИПГ просто как бы подвешивается за входной или выходной узел и используется непосредственно в качестве шаблона для построения вертикального структурного графа, который предусматривает строго иерархическое управление. Получающуюся в результате структурную схему следует рассматривать
как представление каскадного вызова процедур. Если граф подвешен за входной узел, то вызов процедур производится по направлению движения потока данных; если же граф подвешивается за выходной узел, то процедуры вызываются в направлении, противоположном потоку данных. В обоих случаях
Рис. 4.6. Вертикальное управление последовательным потоком данных. («Вертикальная» структурная схема получается непосредственно из диаграммы последовательного потока данных путем «подвешивания ее за один конец».)Рис. 4.6. Вертикальное управление последовательным потоком данных. («Вертикальная» структурная схема получается непосредственно из диаграммы последовательного потока данных путем «подвешивания ее за один конец».)для управления приемом и выдачей данных требуются вспомогательные процедуры GET и PUT.
Рис. 4.6. Вертикальное управление последовательным потоком данных. («Вертикальная» структурная схема получается непосредственно из диаграммы последовательного потока данных путем «подвешивания ее за один конец».)
Рис. 4.6. Вертикальное управление последовательным потоком данных. («Вертикальная» структурная схема получается непосредственно из диаграммы последовательного потока данных путем «подвешивания ее за один конец».)
Альтернативой вертикальному управлению является горизонтальное управление, схематически представленное на рис. 4.7. При этом методе потоком данных между модулями управляет отдельный блок. Хотя и можно непосредственно перейти от исходного ИПГ к горизонтальному структурному графу, показанному на рис. 4.7,6, по-видимому, лучше на практике в общем случае вначале перерисовать информационный граф так, чтобы включить в него управляющий модуль (рис. 4.7, а).
Другой подход заключается в использовании иерархического управления, как показано па рис. 4.8. Здесь (рис. 4.8, а) в
ИПГ включен управляющий модуль, который воздействует только на центральную часть графа, а конечные узлы управляются непосредственно модулями F1 и F3. Иерархический структурный граф, реализующий этот ИПГ, приведен на рис. 4.8,6, где модули Fl, F2 и F3 реализованы в виде блоков с соответствующими процедурами сопряжения GET, CONTROL и PUT. Функции преобразования Fl, F2 и F3 введены в тела этих блоков.
Смешанный подход, представленный на рис. 4.9, включает
отдельные черты принципов горизонтального, вертикального и иерархического управления.
Одной из привлекательных особенностей стратегии проектирования, ориентированной на потоки данных, является то, что ИПГ сами по себе не предопределяют никаких решений в отношении того, будут ли они реализовываться в виде последовательных или иных систем. Значительная часть проекта мо-
И "Горизонтальный" структурный граф.
Рис. 4.7. Горизонтальное управление последовательным потоком данных.
жег быть поэтому выполнена до принятия конкретного решения по данному вопросу. В наших примерах до сих пор приводились структурные графы только для последовательных систем. Однако один и тот же ИПГ может быть использован в качестве основы построения систем как с последовательной,так и с параллельной структурой. На практике нередко по нему бывает проще разработать структурный граф для параллельной системы, чем для последовательной, поскольку часто отсутствует необходимость в явном выделении самостоятельной функции управления.
На рис. 4.10, а приведены два примера структурных схем параллельной системы, которая непосредственно реализует последовательный ИПГ без какого-либо отдельного явно выраженного блока управления. Это возможно потому, что задачи автономны и вообще отсутствует необходимость вводить какую- либо особую иерархию управления на связях структурной
отражающий возможности иерархического управления .
-СЕТ„ДPUT^O,
(6) Иерархический структурный граф в видесовокупности пакетов .
Рис. 4.8. Иерархическое управление последовательным потоком данных^
рит_о
(5) Структурный граф в виде совокупности пакетов.
Рис. 4.9. Смешанное управление последовательным потоком данных.
(а) Поскольку задачи являются автономными, управление в параллельной системе может носить неявный характер независимо от того, в каком направлении взаимодействуют отдельные задачи.
(5) В параллельных системах функции управления могут присутствовать также в явной форме .
Рис. 4.10. Параллельные структурные графы для последовательного потока данных.
схемы. Способ организации связи между парами задач может, следовательно, определяться требованиями конкретного приложения.
Конечно, отдельный блок управления может быть сделан в параллельной системе точно таким же, как и в последователь» ной. Это показано на рис. 4.10,6, где функции модулей F1, F2 и F3 реализуются подчиненными задачами. В этом примере иллюстрируются два подхода к управлению подчиненными задачами:
Подчиненные задачи обращаются к управляющей с запросом на получение каких-либо данных для преобразования.
Управляющая задача обращается к подчиненным с требованием выполнения конкретного преобразования.
Первый подход обычно используется тогда, когда желательно выполнять каждую функцию преобразования параллельно с другими аналогичными функциями. В этом случае преобразованные данные могут возвращаться от подчиненной задачи к управляющей с помощью операции вызова, содержащей запрос на выполнение очередной работы. Второй подход состоит в том, что управляющая задача обращается к подчиненным. Если управляющая задача ожидает завершения преобразования, то
7
Рис. 4.11. Разработка структуры по принципу «от границ — внутрь» для многоканальных потоков данных.
в логическом плане это ничем не отличается от вызова процедур в последовательной системе.
Разумеется, возможно значительно большее разнообразие архитектур параллельных систем, чем было показано на рис. 4.10. Однако мы отложим дальнейшее обсуждение этих вариантов до последующих примеров.
Функционирование вложенных систем вряд ли всегда характеризуется только одинаковым потоком данных. Более вероятен многоканальный поток типа показанного на рис. 4.11, где представлены два первых шага процедуры построения графа многоканального потока данных: первый шаг состоит в идентификации потоков данных через границы системы; второй шаг — это разработка графа внутренних потоков данных, основанная на стратегии «от границ — внутрь». Подробнее мы будем говорить об этом при рассмотрении примеров.
Связь между стратегиями проектирования и испытаний
Как уже упоминалось ранее, в жизненном цикле системы фаза проектирования связана не только с построением архитектуры системы, но и с разработкой плана ее испытаний. Каждой стратегии проектирования соответствует своя стратегия тестирования и испытаний. Так, тестирование может осуществляться сверху — вниз, снизу —■ вверх, изнутри — к границам или от границ — внутрь. Оно может выполняться по отдельным цепям управления или по отдельным каналам данных.
Тестирование сверху — вниз требует наличия фиктивных модулей нижних уровней. При использовании восходящего принципа тестирования необходимо использовать задаклцие модули (драйверы) более высоких уровней. Для тестирования по принципу «изнутри — к границам» нужны и задающие, и фиктивные модули. Тестирование от границ — внутрь подобно тестированию снизу — вверх. Тестирование и испытания должны осуществляться поэтапно таким образом, чтобы полностью проверенные модули постепенно объединялись с непроверенными и другими, уже испытанными модулями для дальнейшей проверки.
Проведение тестирования и испытаний — это отдельная проблема, и ее более глубокое рассмотрение здесь увело бы нас далеко за рамки темы данной главы.
Эскизное представление потока данных:
принципы поэтапной разработки проекта системы
В этом разделе описывается неформальная методология проектирования, в основе которой лежит стратегия структурного проектирования, ориентированная на потоки данных.
При проектировании системы с использованием этой методологии разработчик реализует ряд основных этапов, которые в силу их достаточной общности для любых проектов положены в основу рекомендуемых ниже руководящих принципов. Неформальный характер методологии позволяет определить ее как метод эскизного представления потока данных, который предусматривает следующие шаги разработки:
Шаг 1. Определите в системе наиболее очевидные граничные модули-подсистемы. Центральную часть системы рассматривайте как единый центральный модуль. На этом шаге следует приписывать модулям функции неформально, только в самом общем виде, не слишком беспокоясь об их завершенности или о том, вполне ли они правильны. Целью первого шага является всего лишь обеспечение отправных позиций для организации процесса проектирования. Можно предполагать, что дальнейшие шаги этого процесса выявят необходимость изме-
нения начальных условий; поскольку это вполне естественно и даже неизбежно, слишком большая определенность в исходной точке просто нежелательна. Проектирование всегда отчасти ведется методом проб и ошибок, и поэтому с самого начала должно восприниматься как процесс, сопряженный с постоянным внесением изменений.
Шаг 2. На чистом листе бумаги изобразите выделенные модули для целей их эскизного графического представления. Начните обдумывать характер потоков данных между модулями и оценивать необходимость введения дополнительных внутренних компонентов информационных потоков. Основываясь на этих размышлениях, попытайтесь выявить внутренние модули, которые, по вашему мнению, целесообразно иметь в системе по соображениям обеспечения требуемых функций и модульной конструкции.
Шаг 3. Используйте эскизы информационных потоков и связанные с ними результаты размышлений для того, чтобы уточнить собственные представления о модулях и о потоках данных. Потребность в дополнительных модулях и компонентах потоков данных может стать очевидной, например, вследствие необходимости реализации функций контроля и обработки ошибок.
Шаг 4. С той степенью подробности, какая возможна на данной стадии, припишите модулям конкретные функции, используя перечень технических требований к системе. Снова уточните информационный потоковый граф с учетом произведенного распределения функций. Проведите критический анализ проектных решений по системе на данной стадии и при необходимости внесите изменения.
Шаг 5. Разработайте один или несколько структурных графов, определяя возможные варианты архитектуры системы в виде пакетов и задач для того представления о системе, которое выработалось к данному моменту; основываясь на произведенном распределении функций, определите интерфейсы пакетов и задач в функциональном плане, опуская детали, касающиеся структуры и типов данных. Для задач примите решения относительно направлений рандеву, условий защиты, вспомогательных задач, задач-курьеров, условных и временных вызовов и т. п., следуя руководящим принципам, изложенным в гл. 3. Вновь произведите критический анализ и при необходимости внесите изменения.
Шаг 6. Опишите в деталях интерфейсы системы, в том числе подробности, касающиеся типов и структур данных, и опять проведите критический анализ.
Шаг 7. Если приходится иметь дело с большой и сложной системой, то может оказаться необходимым рекурсивное
применение описанного метода для разработки проектов по подсистемам.
Шаг 8. Необходимо многократно проводить сессии всестороннего сквозного контроля проектных решений, чтобы ведущие специалисты коллектива разработчиков имели возможность убедиться в должном качестве и полноте проекта; эти сессии следует организовывать как рабочие совещания с участием всех основных участников разработки, где заслушиваются сообщения о проектных решениях и даются ответы на все возникающие вопросы. Критерии для оценки проектов рассматриваются ниже в этой главе и в гл. 6.
Рассмотренные основные принципы проектирования систем иллюстрируются ниже на конкретном примере.
Пример разработки проекта: система, реализующая экологическую игру LIFE
Основная причина, по которой в качестве первого примера выбрана игровая система, реализуемая на настольной микроЭВМ в интерактивном режиме, является ее простота; выбрав столь несложный пример, мы можем рассмотреть проблемы проектирования, не заменяя их проблемами конкретной прикладной области.
Главная задача данного примера — показать, каким образом, основываясь на подходе, ориентированном на потоки данных, можно разработать проект системы, которая должна обладать способностью расшифровывать команды, вводимые в интерактивном режиме, и далее реализовать этот проект, используя концепции конечных автоматов, задач и пакетов, предусматриваемых в языке Ада.
Экологическая игра не является игрой в обычном смысле этого слова. Скорее это просто набор правил отображения соответствующих последовательностей рисунков в игровом поле, размеченном на квадраты подобно шахматной доске. В каждом таком квадрате помещаются фишки, которые «живут» или «умирают» в каждом поколении в соответствии с некоторыми правилами в зависимости от наличия или отсутствия других фишек. Последовательное порождение различных конфигураций игрового поля может приводить к возникновению интересных динамических изображений. В нашей системе поле будет высвечиваться на экране дисплея. Предполагается, что размеры поля предопределены программой. Играющий, сидя за клавиатурой, для создания исходной популяции фишек на экране может использовать ряд команд, а затем дать системе задание промоделировать заданное число поколений. В этой главе объектом нашего внимания является проектирование режима
человеко-машинного взаимодействия, а не самого механизма игры.
Конкретные правила рассматриваемой экологической игры несущественны для нашего проекта, однако ради забавы мы их все же приведем. Эти правила основаны на взаимной зависимости каждой фишки и ее соседей, количество которых может доходить до восьми — по числу клеток, окружающих данную. Игра начинается с произвольного числа расположенных в игровом поле в любом порядке фишек, совокупность которых называется исходной популяцией. Следующее поколение определяется путем одновременного применения ко всем клеткам игрового поля двух правил:
Если в некоторой клетке оказывается фишка, то она сохраняется в очередном поколении только тогда, когда имеет ровно двух или трех соседей.
Когда некоторая клетка пуста, в ней помещается фишка, если имеются ровно три соседние занятые клетки.
Предположим теперь, что в руководстве пользователя определена система команд, набираемых из последовательно расположенных слов, которые образуют командные строки. Команды вводятся с клавиатуры посимвольно, и конец командной строки обозначается специальным символом, например сигналом возврата каретки. Слова, образующие команду, отделяются друг от друга пробелами. Команды обрабатываются только после окончания ввода всей строки. На экране резервируется специальная строка для отображения текущей команды по мере ее ввода.
Пусть имеется семь возможных команд, которые образуются последовательностями слов, задаваемых конечным автоматом, как показано на рис. 4.12. Команды 1 и 2 предназначены для заполнения или очистки всех клеток при установке начального состояния. Команды 3 и 4 определяют способ интерпретации пар чисел в командах 5 и 6, указывающих номера строк и столбцов. Команды 5 и 6 добавляют или удаляют фишки в клетках с координатами, определяемыми парой.этих чисел. Команда 7 определяет задаваемое число поколений. Наша задача теперь состоит в том, чтобы спроектировать систему, которая будет распознавать эти команды при вводе, отвергать последовательности символов и слов, которые не образуют распознаваемых команд, а также определять порядок выполнения соответствующих операций по заполнению или очистке игрового поля, размещению фишек в игровом поле для создания исходной популяции, добавлению или удалению фишек на экране с целью порождения новой исходной популяции в игре и моделированию процесса рождения и гибели заданного числа поколений,
Рис. 4.12. Конечный автомат для последовательности слов командной строки в системе LIFE. (Примечание. Не производится никаких действий при любых транзакциях, кроме тех, которые содержат параметр <ЧИСЛО>. Для них следует сохранить указываемое число в одной из двух ячеек.)
Поток данных
Последующая разработка информационного потокового графа системы LIFE проводится в соответствии с процедурой эскизного графического представления потока данных, рекомендованной в разд. 4,3..
На границах системы необходимо иметь следующие модули: • модуль приема данных, вводимых с клавиатуры,
модуль фиксатора-дешифратора строки, предназначенный для запоминания частично заполненных командных строк с целью их высвечивания в специальной зоне экрана и для декодирования законченных командных строк,
модуль хранения игрового поля, предназначенный для запоминания информации, которая необходима для отображения на экране текущего состояния игрового поля и для генерации новых игровых полей, подлежащих выводу на экран.
Во внутреннем потоке данных можно выделить следующие существенные элементы:
вводимые символы, которые должны компоноваться в командные строки,
, • декодированные команды,
сообщений и ответов)
Рис. 4.13. ИНГ для системы LIFE.
Вывод строки на экран
Рис. 4.14. Пошаговое уточнение ИПГ системы LIFE,
• запросы вывода на экран наводящих сообщений, строк символов и ответов,
- запросы вывода на экран новых конфигураций и игрового поля.
Для того чтобы соединить эти элементы потока данных вместе, требуется по крайней мере еще один дополнительный модуль, а именно процессор команд, предназначенный для преобразования декодированных команд в запросы вывода на экран картины игрового поля. Определенный выше модуль фиксатора-дешифратора строки осуществляет преобразование символов в декодированные команды (рис. 4.13).
Добившись четкого и полного представления об информационном потоковом графе, целесообразно уточнить структуру модуля фиксатора-дешифратора строки. Поскольку командные строки при декодировании рассматриваются как цепочки слов, представляется целесообразным разделение фиксатора-дешифратора строки на фиксатор строки и дешифратор цепочки слов; результат этой операции показан на рис. 4.14. Предполагается, что словарь командных слов является частью модуля фиксатора строки, который преобразует цепочку символов, ограниченную пробелами, в код слова. Элемент потока данных между фиксатором строки и дешифратором цепочки слов команды, являющейся цепочкой слов, может быть одной строковой переменной или некоторой последовательностью переменных, представляющих собой коды командных слов; однако все это — подробности, которые на данном этапе проектирования могут игнорироваться. .
Структура системы
Из построенного ИПГ довольно просто получить структурный граф, причем здесь первая задача заключается в том, чтобы решить, какова природа модулей, присутствующих в ИПГ. Модуль приема данных с клавиатуры должен представлять собой задачу, если символы вводятся по сигналам прерывания. Модули фиксации строки и хранения игрового поля могут быть пакетами, поскольку регенерация изображения на экране осуществляется непосредственно из памяти аппаратными средствами и для управления их работой не требуется порождать задачу. Отметим, однако, что в целях более широкого представления функций системы задача управления экраном должна быть определена как часть проекта системы, даже если она реализуется аппаратными средствами; тем не менее мы будем предполагать, что аппаратные средства заданы. Поскольку вообще задачи обслуживания прерываний следует делать максимально простыми, функции управления системой не следует возлагать на задачу приема данных с клавиатуры.
Рис. 4.15. Структурный граф системы LIFE.
Поэтому возникает необходимость в еще одной, внутренней задаче системы, обеспечивающей сопряжение с модулем ввода и управление системой. Здесь возможны несколько подходов. Самый простой из них состоит в том, чтобы «подвесить» информационный потоковый граф за некоторую вершину, близкую к его середине. Подходящая точка находится между модулем фиксатора-дешифратора строки и модулем процессора команд. Для обеспечения общего управления в этом узле графа может быть организована задача. Заметим, что эта задача не обеспечивает никаких новых функциональных возможностей; она просто реализует нужный маршрут движения потока данных, и на схеме ИПГ не требуется показывать никакого соответствующего ей модуля. Модуль дешифратора цепочки слов теперь уместно объявить пакетом. Результат всех выполненных действий приведен на рис. 4.15.
Функционирование системы, которую описывает построенный структурный граф, представляется следующим образом. Когда задача LIFE запускается, она прежде всего вызывает процедуру GET-COMMAND (ПОЛУЧИТЬ-КОМАНДУ) из па-
кета фиксатора-дешифратора строк, которая в свою очередь многократно обращается к процедуре GET-CHAR (ПОЛУ- ЧИТЬ-СИМВОЛ) из задачи приема данных с клавиатуры, пока все символы строки не будут собраны воедино и заполнены внутри пакета фиксатора строк; команда затем декодируется, и ее код возвращается в качестве выходного параметра вызова для процедуры СЕТ-COMMAND совместно с любыми
Рис. 4.16. Проработка внутренних деталей фиксатора строки.
Условные обозначения:
LINE-STORAGEПАМЯТЬ-СТРОК
RESPONSE DICTIONARYСЛОВАРЬ ОТВЕТНЫХ СООБЩЕНИЙ
COMMAND WORD DICTIONARY СЛОВАРЬ КОМАНДНЫХ СЛОВ
другими параметрами той же команды (такими, как число моделируемых поколений).
Заметим попутно, что задача LIFE может находиться в состоянии ожидания очередного символа.
После возврата из вызова процедуры NEXT-LINE (СЛЕ- ДУЮЩАЯ-СТРОКА) пакет дешифратора с помощью внутренних механизмов многократно вызывает процедуру GET— WORD-ID (ПОЛУЧИТЬ-ИДЕНТИФИКАТОР-СЛОВА), пока не будет получена распознаваемая либо нераспознаваемая команда. Сообщения об ошибках в командах и наводящие сообщения для ввода очередных команд обрабатываются внутренними средствами с помощью процедуры DISPLAY (ВЫ- ВОД_НА_ЭКРАН).
Когда команда декодирована, задача LIFE вызывает пакет процессора команд, передавая ему идентификатор соответству-
ющей команды и нужные параметры. Далее выполнение затребованной командой функции возлагается на пакет процессора команд, который при необходимости обращается к пакету храпения игрового поля.
Следующий шаг проектирования — это внутренняя разработка отдельных модулей. В качестве примера достаточно будет разработать структурные графы для внутренних механизмов пакета фиксатора строки и пакета дешифратора команд. На рис. 4.16 и 4.17 показаны возможные варианты внутренней структуры обоих пакетов.
В представленной на рис. 4.16 структурной схеме пакета фиксатора строки процедура GEELINE (ПОЛУЧИТЬ- СТРОДУ) циклически вызывает процедуру GET-CHAR. Внутренний маркер указывает положение следующего слова, доступного для поиска идентификатора с помощью процедуры GET_WORD_ID, которая реализует просмотр следующего слова (смещая одновременно маркер), сопоставляет это слово с внутренним словарем и передает найденный идентификатор слова вызывающей программе. Поскольку в рассматриваемом пакете не предусматривается никакой явной обработки ошибок, следует иметь по крайней мере одно зарезервированное значение идентификатора слова для случая нераспознаваемого слова.
Результат внутреннего проектирования пакета дешифратора команд приведен на рис. 4.17 в виде структурного графа и скелета программы. Этот пакет включает внутренний пакет FSM (КОНЕЧНЫЙ АВТОМАТ), который содержит информацию о текущем состоянии, таблицы состояний конечного автомата и процедуру NEXT, осуществляющую обращение к этим таблицам с целью корректировки состояния по данному событию. Возвращаемыми параметрами процедуры NEXT являются коды состояния и действия, которые используются процедурой GET_COMMAND_ID для решения вопроса о том, декодирована ли уже команда и следует ли сохранить какие-либо параметры.
Оценка проектных решений
В ходе сессии сквозного структурного контроля проектных решений могут быть поставлены следующие типичные вопросы, касающиеся качества проекта:
Сможет ли проектируемая система легко обеспечивать опережающий прием символов с клавиатуры? Опережающий прием — это свойство системы, которое позволяет быстро работающему оператору «обгонять» систему без риска потери набираемых на клавиатуре символов. Маловероятно, что отсутствие
Структурный графь
package COMMAND-DECODER is
type RESULT—TYPE (COMMAND-ID : integer) is record
case COMMANDID is
when 1 .. 4 = > hull;
when 5 .. 7 = >PARAMS : array (1.. 2) of integer;
end case;
end record;
procedure GET_COMMAND (RESULT : out RESULT_TYPE)j
end COMMAND—DECODER;
package body COMMANDDECODER is
package FSM is
type WORD_ID_TYPE (WORD—CODE : t..) is
record
case WORD—CODE is
when .,, = > null;
when ,,, = >VALUE : integer;
end case;
end record;
procedure NEXT (WORD_ID : in WORD_ID_TYPE}
RESULT I out RESULT—TYPE);
end FSM;
package body FSM is separate;
Условные обозначения:
SAVE VARIABLEСОХРАНЯЕМЫЕ ПЕРЕМЕННЫЕ
FSM-TABLESТАБЛИЦЫ СОСТОЯНИЙ KA,
procedure GET_COMMAND (RESULT : out RESULT_TYPE) is
begin
Joop
LINE_HOLDER.GET (*ORD_IO):
if WORD_JD.WORD_.CODE = NO_MORE
then exit; end if;
FSM.NEXT (WORD_ID, RESULT);
end loop;
if RESULT .COMMANDED = .„then,.,;ОШИБКА
end GET_COMMAND;
end COMMAND_DECODER;
Separate COMMANDDECODER
package FSM is
STATE : integer; = 8;
EVENT, ACTION : integer;
SAVE : array (1 .. 2) of integer;
S__TABL : array (EVENT. STATE) of integer.
: =МАССИВ СОСТОЯНИЙ
A__TABL : array (EVENT. STATE) of integer: =МАССИВ ДЕЙСТВИЙ
procedure NEXT^WORD_ID ; in WORD_ID_TYPE;
'RESULT ; out RESULT_TVPE) is
begin
EVENT : = WORD_ID.WORD_CODE;
ACTION ; =A_TABL (EVENT, STATE):
STATE :=S_TABL "(EVENT, STATE);
case ACTION is when 1 = > null;
when 2 = > SAVE(1): = WORD_ID. VALUE;
when 3 = > SAVE(2): = WORD_ID.VALUE;
end case:
RESULT.COMMAND_ID ; = STATE;
if STATE in 5 .. 7
then RESULT,PARAMS : - SAVE;
end if;
end NEXT;
end FSM;
Скелет Ада-программы.
Рис. 4.17. Проработка внутренних деталей дешифратора команд, а) структурный граф, б) скелет программы на языке Ада.
опережающего приема в рассматриваемой простой системе станет источником каких-либо проблем, однако оно может вызывать серьезные затруднения в системах, в которых обработка вводимых символов иногда затягивается, скажем, из-за необходимости обращения к внешнему ЗУ.
Можно ли будет легко модифицировать систему, чтобы обеспечить немедленное (вплоть до позиции текущего символа) оповещение оператора об обнаруживаемой некорректности цепочки символов, не дожидаясь конца строки?
Предусматривает ли проект системы удобные процедуры изменения командных слов, допустимых последовательностей слов в командных цепочках и семантической структуры команд? Подобные изменения часто требуется вносить в течение всего жизненного цикла системы.
Что касается опережающего приема символов, то, очевидно, проще всего поместить в задачу приема данных с клавиатуры буфер опережающего ввода для накопления символов в случаях, когда система недостаточно быстро вызывает процедуру GET_CHAR, чтобы стереть текущий символ до прихода следующего.
Немедленное оповещение об ошибке является более сложной проблемой. Чтобы иметь систему, способную уведомлять оператора об ошибках в команде тотчас после ввода символа, который в контексте введенной до этого момента командной последовательности является некорректным, следует несколько модифицировать внутренний проект пакета фиксатора-дешифратора строки. Основное необходимое изменение заключается в замене дешифратора команд, анализирующего цепочку слов, на дешифратор, анализирующий цепочку символов.
Рассматриваемую систему не так уж легко модифицировать в части обеспечения ее приспособляемости к изменениям в командах, поскольку словарь командных слов и таблицы последовательностей слов для конечного автомата принадлежат разным пакетам. С этой точки зрения было бы лучше поместить эти информационные объекты в один и тот же пакет и иметь в виду предложенный выше дешифратор команд, который анализирует последовательность символов, обеспечивая лучшие начальные условия для разработки качественного проекта.
Обратим, однако, внимание на то, что представленное на рис. 4.15 проектное решение получено как результат сформулированного в явном виде требования к пользовательскому интерфейсу обрабатывать команды в реальном масштабе времени. Такое определение интерфейса пользователя привело к разработке проекта, который ограничивает гибкость системы. В качестве общего правила отметим, что в случае, когда важна гибкость системы, это должно быть сформулировано в виде отдельного требования; в противном случае разработчик может прийти к решению удовлетворить определенно сформулированные требования ценой ограничения гибкости системы.
Следует также ответить на вопрос: удалось ли максимально упростить структуру системы и не содержит ли она каких- либо излишних, не оправданных назначением проекта интерфейсов или избыточных модулей? Вновь обратившись к рис. 4.15, мы сразу обнаруживаем, что проект в целом может
быть несколько упрощен за счет исключения в некотором смысле избыточного вызова процедуры GET_COMMAND при обращении из задачи LIFE к пакету дешифратора цепочки слов команды. Упрощение может быть достигнуто путем исключения упомянутого пакета и передачи его функций телу задачи LIFE. Этот подход равнозначен подвешиванию ИПГ, представленного на рис. 4.13 и 4.14, за модуль дешифратора цепочки слов команды и преобразованию этого модуля в задачу. Конечно, для данного конкретного примера ответ на вопрос о том, стала ли новая структура лучше прежней, является, вероятно, делом вкуса. Важно, однако, чтобы подобные вопросы не оставлялись без внимания в ходе проектирования.
Пример разработки проекта:
система FORMS, реализующая форматированный ввод и вывод данных
Цель этого примера заключается в том, чтобы рассмотреть несколько более сложные проблемы проектирования, чем в очень простом примере системы LIFE. Эта дополнительная сложность возникает из-за необходимости координировать видимые оператору действия системы, происходящие на «переднем плане», с параллельно протекающими фоновыми операциями, которые порождаются «передним планом», но невидимы оператору.
Система FORMS требуется для подготовки, редактирования и печати деловых документов. В целях упрощения системы предполагается, что в ней нет никаких запоминающих устройств для хранения файлов, и поэтому единственное, что она позволяет делать, — это подготавливать на экране один деловой документ и распечатывать его непосредственно из основной памяти по хранящемуся там информационному отображению.
Редактирование формы относится к операциям переднего плана в том смысле, что оператор определенным образом инициирует все функции редактирования документа и ожидает их выполнения. В то же время печать формы может быть функцией как переднего плана, так и фоновой. В первом случае оператор должен запрашивать печать изображенного на экране готового документа и затем ожидать завершения его печатания.
Во втором случае печать может происходить параллельно с операциями редактирования формы на экране. Один из подходов к решению этой проблемы состоит в том, чтобы обеспечить
хранение в основной памяти нескольких форм и выполнять операции редактирования одной из них одновременно с печатанием другой, уже заполненной. Альтернативный подход (и именно он использован в данном примере) заключается в одновременном выполнении редактирования как работы переднего плана и фоновой печати одной и той же формы; при этом, однако, операциям редактирования доступны лишь незаконченные части документа, а печатаются только полностью
Рис. 4.18. Поля бланка документа. (Примечание. Номера полей не являются частью их текста.)
завершенные разделы. Таким способом можно максимально ускорить печатание формы, поскольку для этого не надо ждать, пока оператор закончит заполнение всего документа. Рассмотренный подход порождает интересную задачу координации редактирования и печати по причине различия логических представлений одной и той же формы в рамках двух разных функций. В плане редактирования форма документа —■ это просто совокупность полей данных; в аспекте печати форма — это набор строк, имеющих длину, равную ширине страницы.
Для целей данного примера деловой документ можно рассматривать с двух совершенно разных точек зрения (рис. 4.18):
— как совокупность прямоугольных полей различного размера и конфигурации, каждое из которых имеет определенное местоположение на странице и содержит строки текста, расположенные внутри контуров поля (строки поля);
•— как совокупность строк на странице (строки страницы),
Поля данных могут быть уже, чем полная ширина страницы, и, следовательно, могут включать фрагменты нескольких строк страницы. Одна строка страницы может содержать несколько строк полей. Предполагается, что границы полей образуются горизонтальными и вертикальными рядами звездочек, наименования полей являются частью содержащегося в них текста, а поля размещаются на странице плотно, т. е. между ними нет промежутков, как нет и пустых строк между полями данных и границами страницы.
Чтобы обеспечить одновременное редактирование и печать одной и той же формы, поля нумеруются последовательно слева направо и сверху вниз; любое поле может редактироваться только в этой установленной последовательности, и если данное поле уже отредактировано, то повторный доступ к нему для редактирования оказывается невозможным, пока не будет завершено редактирование всей совокупности полей. Строки страницы печатаются сразу, после того как они становятся недоступными для дальнейшего редактирования, до окончания заполнения всей формы. Поскольку документ подготавливается последовательно, поле за полем, строка страницы оказывается заполненной тогда, когда заполнены все поля, которые она пересекает. .
Управление редактированием осуществляется с помощью двух специальных функциональных клавиш следующим образом:
. После нажатия функциональной клавиши START-EDIT (НАЧАЛО-РЕДАКТИРОВАНИЯ) вводится трехзначное число, определяющее номер подлежащей редактированию формы. В результате этого на экране высвечивается незаполненная форма с подготовленным для ввода информации полем 1; специальный номер формы ООО указывает на повторное редактирование того же самого текущего документа. Сигнал от клавиши START-EDIT распознается только непосредственно после включения системы или когда завершается печать текущей формы.
Функциональная клавиша NEXT-FIELD (СЛЕДУЮЩЕЕ-ПОЛЕ) используется оператором для сигнализации об окончании заполнения текущего поля и перевода курсора на начало следующего по порядку номеров поля. Таким образом, система узнает об окончании редактирования поля, когда она обнаруживает факт нажатия клавиши NEXT-FIELD.
Текущая позиция для редактирования всегда указывается курсором. Высвечивание курсора на экране реализуется автоматически аппаратными средствами. Положением курсора управляют программные средства, работающие независимо от программы ввода символов данных.
В пределах некоторого поля ввод и редактирование выполняются путем занесения символа в ту позицию, которая в данный момент указывается курсором, с использованием при необходимости функциональной клавиши BACKSPACE (ВОЗВРАТ) для перемещения курсора назад внутри поля. По мерс ввода символов курсор сдвигается вправо на одну позицию. Клавиша BACKSPACE просто обеспечивает возврат курсора назад на одну позицию без изменения содержимого поля. В целях упрощения программных средств вставка пропущенных символов осуществляется путем печатания их поверх уже существующих с последующим повторным вводом оставшейся части текста поля; удаление ненужных символов производится путем возврата назад и печатания на их месте пробелов.
Система отслеживает границы полей данных и контролирует правильность операций, соответствующих этим границам. При движении вправо курсор на правой границе поля перебрасывается в начало следующей строки того же поля, а при движении влево он на левой границе устанавливается на конец предыдущей строки поля; все эти действия реализуются программным способом. Курсор не может перемещаться дальше из самой верхней левой и самой нижней правой позиций поля. Любая попытка сдвинуть его в неверном направлении в этих положениях, кроме случая использования клавиши NEXT-FIELD, является ошибкой
При обнаружении какой-либо ошибки система должна давать звонок и прекращать выполнение команды, вызвавшей ошибку. '
Описанный выше интерфейс пользователя по соображениям удобства обучения умышленно сделан предельно простым и в определенных аспектах не особенно хорош. Однако пока для наших целей этого достаточно, и мы отложим его критику до момента оценки проекта.
В системе необходимо также иметь таблицы, описывающие различные формы документов. В условиях отсутствия внешней памяти они должны запоминаться в первичном ПЗУ и, следовательно, становятся доступными сразу после включения системы. При этом команда START-EDIT идентифицирует ту из таблиц, которая подлежит использованию для вывода на экран нужного бланка документа и для последующего его редактирования. Таблицы описания форм должны содержать сведения о размерах и местоположениях каждого поля формы, а также о последовательности просмотра полей при редактировании. В этих таблицах должна, кроме того, присутствовать для каждого поля информация о строках страницы, освобождаемых для печати. Например, на рис. 4.18 поля 1 и 2 не освобождают ни одной строки страницы; поле 3 освобождает строки I
и 2; поле 4 не освобождает ни одной строки страницы; поле 5 освобождает строки 3 и 4; поле 6 — страничную строку 5 и т. д. Подобные перечни освобождаемых строк по каждому полю отражают неотъемлемые, неизменяемые свойства каждой конкретной формы и могут поэтому быть частью таблиц описания форм.
Поток данных для редактирования
Следуя руководящим принципам разд. 4.3, можно разработать информационный потоковый граф для рассматриваемой системы по схеме «от границ — внутрь». На рис. 4.19 показано первое представление ИПГ: от границ внутрь системы направлены потоки сигналов, снимаемых с клавиатуры, информация о структуре и характеристиках документа из таблицы описания текущей формы, а также символы или строки страницы, пересылаемые из памяти дисплея для печати. Потоки изнутри
Рис, 449. Первое представление ИПГ системы FORMS,
системы к ее границам — это запросы звонка, символы, которые подлежат занесению в память дисплея (заметим, что к их числу относятся данные, обеспечивающие отображение курсора), и строки страницы для подсистемы построчной печати. Изнутри системы исходят также запросы на печать строк страницы. Здесь предполагается, что фактические строки страницы для печати поступают непосредственно из памяти дисплея под управлением блока, отличного от механизма выдачи запросов на печать строк страницы; это предположение вполне логично, если принять во внимание способ освобождения строк страницы для печати путем последовательного просмотра полей.
Теперь остается разработать внутренние элементы ИПГ для «средней части» системы. Однако в отличие от системы LIFE в данном случае ИПГ не является однолинейным. Поскольку параллельно выполняется несколько функций, в системе имеется несколько параллельных потоков. В качестве общей стратегии представляется разумным первоначальное рассмотрение таких параллельных ветвей по отдельности. В данном случае логично начать с рассмотрения той ветви, которая соответствует выполняемой на переднем плане функции редактирования формы.
На рис. 4.20 показан расширенный ИПГ для выполняемой на переднем плане функции редактирования и вывода формы документа. Основной принцип, на основе которого строится этот граф,— раздельное управление логическим и физическим дисплеем. Управление логическим дисплеем связано только с обработкой и редактированием форм. На этом уровне формы рассматриваются как логические объекты независимо от того, каким образом они физически выводятся на экран. Управление физическим дисплеем, наоборот, связано лишь с такими элементами, как положение курсора на экране, занесение символов по абсолютному адресу местоположения на экране, поиск физических строк для печати и т. д. Управление физическим дисплеем не затрагивает логической интерпретации того, что выводится. Если положить в основу указанное разделение функций управления, то ИПГ получается естественным образом путем добавления модуля- дешифратора событий между потоком сигналов от клавиш и запросами на обращение к логическому дисплею, модуля управления выводом между потоком обращений к логическому дисплею и запросами доступа к физическому дисплею; на конце ветви должен быть помещен модуль управления физическим дисплеем. Мы используем здесь термин «дешифратор событий», а не «дешифратор команд» потому, что хотим обеспечить возможность взаимодей-
ствия этого модуля и с фоновой функцией печати. В таком виде он в результате будет связан не только с командами оператора, но и с событиями в системе печати.
Представление структуры для функции редактирования
Весьма просто преобразовать полученный ИПГ в соответствующий структурный граф. Следуя принципам, изложенным в подразд. 4.4.3, мы сделаем модуль дешифратора событий задачей. Модуль управления логическим дисплеем нет необходимости оформлять как задачу, поскольку он используется дешифратором событий исключительно для выполняемой на переднем плане функции редактирования. Между функцией управления логическим дисплеем и фоновой функцией печати никогда не возникает никакого взаимодействия, поэтому можно сразу принять решение, что управление логическим дисплеем будет реализовано как пассивный пакет.
При условии, что задача дешифратора событий осуществляет всю координацию между функциями переднего плана и фоновыми, относящимися к печати строк, отсутствует возможность конфликта между операциями доступа к управлению физическим дисплеем для целей редактирования и доступа к нему для поиска строк, подлежащих выводу на печать. Только в таком случае на данном этапе проектирования можно принять решение о том, что управление физическим дисплеем будет также реализовано пассивным пакетом. В противном случае могут возникать неприемлемые конфликты. Пока что мы будем считать модуль управления физическим дисплеем пассивным пакетом, а к вопросу о том, может ли возникнуть конфликтная ситуация, вернемся позже.
На рис. 4.21 показаны внешние связи и внутренняя структура пакета управления логическим дисплеем. Он включает три интерфейсные процедуры, а именно NEW-FORM (НОВАЯ ФОРМА), NEXT-FIELD (СЛЕДУЮЩЕЕ-ПОЛЕ) и EDITFIELD (РЕДАКТИРОВАНИЕ-ПОЛЯ). Обращение к процедуре NEW-FORM должно предусматривать в качестве параметра номер формы. Внутри себя процедура NEW-FORM осуществляет доступ к той таблице описания формы, которая определяется номером этой формы, чтобы вывести на экран ее бланк (если номер формы не равен ООО), и устанавливает курсор в левый верхний угол первого поля этой формы (исходное положение). Ошибка в номере формы приводит к возврату из процедуры с указанием неверного параметра. Процедура NEXT-FIELD не требует передачи входных параметров, поскольку очередное поле определяется таблицей описания формы. Информация о требуемом положении курсора поступает в тело процедуры NEXTFIELD из таблицы описания формы, после чего курсор переводится в указанное положение. Из тела процедуры NEXT-FIELD нужный номер поля пересылается внутреннему пакету редакти-
Буквенно-цифровойсимвол или пробел
Выбрать из памяти таблицу Определить требуемое положение Ввести символ в Идентифицировать Проверить Переместить описания формы, высветить курсора по таблице описания физический физическоепо таблице курсор
на экране пустой бланкформы и переместить курсор дисплей положение описания формы,
(если номера ООО) и установитькурсора не вышел ли курсор
курсор в начальное положениепосле перемещения
за границы поля
Рис. 4.21. Внешнее и внутреннее представления пакета управления логическим дисплеем.
рования, который будет осуществлять детальное редактирование внутри данного поля.
Процедура EDIT-FIELD получает в качестве входного параметра код символа (любой буквенно-цифровой символ или символ возврата) и выдает в качестве результата код ошибки, когда неверен входной символ или выполнение функции редактирования приводит к нарушению границ поля. Телом процедуры EDIT-FIELD просто передается конкретный символ
Рис. 4.22. Внешнее представление пакета управления физическим дисплеем.
интерфейсной процедуре ENTER-CHAR внутреннего пакета редактирования поля.
Внутренний пакет FIELD-EDIT получает информацию о том, какое поле является текущим, с помощью процедуры SET-FIELD (УСТАНОВИТЬ-ПОЛЕ) и поэтому может реали- вать контроль таблицы описания текущей формы в отношении нарушения границ с помощью внутренней процедуры их проверки. Для установления текущего физического положения курсора, вывода символа на физический экран и перемещения курсора этот пакет обращается к пакету управления физическим дисплеем.
На рис. 4.22 дано минимальное внешнее представление этого пакета, предусматривающее необходимый для управления логическим дисплеем сервис. Эти служебные функции обеспечиваются интерфейсными процедурами ENTER-CHARACTER (ВВЕСТИ-СИМВОЛ), CLEAR-DISPLAY (ОЧИСТИТЬ- ЭКРАН), MOVE-CURSOR (ПЕРЕВЕСТИ-КУРСОР) и CHECKCURSOR (ПРОВЕРИТЬ-КУРСОР).
Поток данных для вывода на печать в фоновом режиме
На рис. 4.23 дано детальное представление ИНГ в соответствии с требованиями к выполнению печати в фоновом режиме, Из рисунка видно, что для реализации этих операций
не нужны никакие новые модули, но необходимы некоторые дополнительные потоки данных. На рис. 4.23 опущены все потоки данных, которые связаны исключительно с функцией редактирования. Проследим за формированием запроса NEXTFIELD. Сначала прерывание, вызываемое набором символов NEXT-FIELD, воспринимается интерфейсом клавиатуры, и код этого набора символов пересылается дешифратору событий, который в свою очередь адресует запрос NEXT-FIELD модулю управления логическим дисплеем. На основании информации, полученной из таблицы описания текущей формы, этот модуль сообщает дешифратору событий диапазон (N...M) номеров строк страницы для печати. Дешифратор событий пересылает этот диапазон номеров строк построчно-печатающему устройству, которое принимает очередную строку страницы от пакета управления физическим дисплеем, печатает ее и затем посылает обратно дешифратору событий уведомление MORE-LINES (СЛЕ- ДУЮЩИЕ-СТРОКИ). '
Теперь становится ясным отличие дешифратора событий от дешифратора команд; назначение дешифратора событий состоит в обработке двух типов событий, а именно сигналов, поступающих от интерфейса клавиатуры, и уведомлений MORE- LINES — от построчно-печатающего устройства.
Что же касается дешифратора команд, то его функции не столь сложны: он должен выполнять распознавание команд и их обработку; каждая из этих функций предполагает правильное управление формированием различных последовательностей событий. Поэтому представляется желательной дальнейшая детализация модуля дешифратора событий.
Более подробно этот модуль представлен на рис. 4.23, б. Указанные выше функции выполняются здесь раздельными модулями: распознавателем команд и процессором команд с единым управляющим модулем, играющим роль координатора. Управляющий модуль пересылает сигналы нажатия клавиш распознавателю команд, который в свою очередь в процессе печатания сообщает коды команд процессору команд. Последний передает управляющему модулю диапазон (N ... М) строк, которые подлежат выводу на печать по окончании работы с конкретным полем. Управляющий модуль связан с модулями интерфейса клавиатуры и построчно-печатающего устройства, а процессор команд — с модулем управления логическим дисплеем. Заметим Попутно, что управляющий модуль должен обязательно получать сигнал о том, что строк для печати больше нет.
На рис. 4.24 представлены конечные автоматы, реализующие функции модулей распознавателя команд и процессора команд. Команды редактирования формируются при нажатии
одиночных клавиш и поэтому распознаются сразу. Команды START-EDIT требуют нажатия нескольких клавиш и, следовательно, нескольких стадий распознавания. Конечный автомат процессора команд необходим для того, чтобы предотвратить редактирование новой формы, пока не будет завершено печатание предыдущей. Событиями, вызывающими изменение состояния конечного автомата, являются получение команды START-EDIT, прием команды NEXT-FIELD, когда заполнено последнее поле формы, и поступление сигнала уведомления об окончании печати. Казалось бы, уведомление о новом диапазоне номеров строк страницы для печати должно тоже считаться отдельным событием. Однако на самом деле оно является прямым результатом набора команды NEXT-FIELD и потому обрабатывается как часть этого события. Назначение пунктирных линий на схеме конечного автомата процессора команд поясняется ниже.
Одно из наиболее неприятных обстоятельств, которое может возникнуть при функционировании интеллектуальной рабочей станции,—■ это отсутствие реакции устройства на нажатие кла-
(а) Схема взаимодействий при печати строк страницы,
Нажатие клавиш(к)
‘1 (б) Внутренний поток данных дешифратора событий
Рис. 4.23. Детальное представление ИПГ.
виш клавиатуры. Такое может случиться, если не предусмотреть связи, отмеченные на рис. 4.24 в схеме конечного автомата процессора команд пунктирными линиями. Эти связи обеспечивают в явной форме отклонение (а не игнорирование)’ команд редактирования в состоянии ожидания и выход из этого состояния, если печатающее устройство не проявляет никакой реакции. Соответствующие связи изображены пунктиром по той причине, что ранее мы не включили рассмотренную возможность в спецификацию команд (типичный пример ошибки в технических требованиях, выявляемой в процессе проектирования) .
Здесь следует обратить внимание на то, что нам удалось детализировать функциональное назначение основных модулей системы и их взаимодействий без принятия каких-либо решений относительно представления конкретных модулей в виде пакетов или задач, и без ответов на вопросы, какой модуль каким вызывается и сколько вызовов необходимо, чтобы реализовать нужный поток данных. Таким образом, подход к проектированию, основанный на рассмотрении в первую оче~
(а) Состояния распознавателя команд ,
(б) Состояния процессора команд.
Рис. 4.24. Схема конечного автомата для дешифратора событий.
редь потока данных, позволяет отложить принятие решений по этим существенным организационным деталям. Поэтому решения, уже принятые ранее в разд. 4.5.2, вполне можно было бы отложить до завершения построения схемы потока данных.
Структурная схема взаимодействий при фоновой печати
Теперь мы в состоянии приступить к определению общей структуры взаимодействий задач при фоновой печати. Рассмотрим сначала взаимодействие между задачей интерфейса клавиатуры и задачей дешифратора событий. Один из подходов мог бы состоять в том, чтобы в задаче дешифратора событий организовать обращение к входу GET „KEYSTROKE задачи обработки прерываний от клавиатуры, переводя ее тем самым в режим ожидания сигнала нажатия клавиши. Такой подход
имеет то преимущество, что вызов задачи обработки сигналов прерываний от клавиатуры никогда не может быть задержан обстоятельствами, влияющими на другую задачу, которая была вызвана этой. Другой подход состоит в том, чтобы задача обработки прерываний от клавиатуры вызывала задачу дешифратора событий для передачи ей сигнала нажатия клавиши. В данном случае задача дешифратора событий не будет игнорировать другие события из-за того, что она ожидает в это время сигналы от клавиш, — ив этом заключается преимущество второго подхода. Однако здесь, несомненно, имеет место одна из тех ситуаций, когда каждая из задач слишком важна, чтобы вызывать другую (см. гл. 3). Между такими задачами должна вводиться задача-курьер.
Двунаправленный поток данных между задачей построчно- печатающего устройства и задачей дешифратора событий может быть легко реализован при помощи однонаправленного обращения задачи построчно-печатающего устройства к входу задачи дешифратора событий с ожиданием очередных строк для печати. Этот вызов сам по себе играет роль уведомления о том, что печать предыдущего набора строк закончена. В качестве выходного параметра этого вызова может быть возвращен диапазон номеров строк страницы для нового набора строк. Результирующая структура показана на рис. 4.25, а.
Для более убедительного обоснования целесообразности использования задачи-курьера в случае событий, связанных с клавиатурой, рассмотрен один конкретный сценарий. При непосредственном обращении дешифратора событий к интерфейсу клавиатуры может иметь место следующая цепочка событий. Пока задача построчно-печатающего устройства занята печатанием первых строк формы, операции редактирования, выполняемые под управлением задачи дешифратора событий, могут успешно завершиться освобождением еще нескольких строк. Диапазон их номеров будет зафиксирован внутри дешифратора событий с целью пересылки этих сведений устройству построчной печати по получении вызова MORE-LINES. Допустим, что в это время оператор над чем-то задумался, а задача дешифратора событий ожидает между тем следующего нажатия клавиши. Предположим далее, что задача построчно- печатающего устройства запросила очередные строки до того как оператор нажал очередную клавишу. Поскольку задача дешифратора событий все еще находится в состоянии ожидания, задаче построчно-печатающего устройства тоже придется ждать, хотя нужные строки уже имеются. Но задача построчно-печатающего устройства не получит их для печати, пока оператор не нажмет следующую клавишу, освобождая задачу дешифратора событий для обработки этого сигнала от клавиа-
туры и приема запроса MORE-LINES. Крайне маловероятно, что эта небольшая дополнительная задержка печати окажет существенное влияние на функционирование данной системы. Однако заметим, что пренебрегая ею как несущественной, мы делаем молчаливое предположение о наличии синхронизации
(а) Структурный граф .(а) Структурный граф .Рис. 4.25. Верхний уровень взаимодействий модулей системы FORMS при пе-Рис. 4.25. Верхний уровень взаимодействий модулей системы FORMS при пе-КЛАВИАТУРАПОСТРОЧНО-ПЕЧАТАЮЩЕЕ УСТРОЙСТВОУПРАВЛЕНИЕ-ФИЗИЧЕСКИМ- ДИСПЛЕЕМКЛАВИАТУРАПОСТРОЧНО-ПЕЧАТАЮЩЕЕ УСТРОЙСТВОУПРАВЛЕНИЕ-ФИЗИЧЕСКИМ- ДИСПЛЕЕМ
(а) Структурный граф .
(а) Структурный граф .
Рис. 4.25. Верхний уровень взаимодействий модулей системы FORMS при пе-
Рис. 4.25. Верхний уровень взаимодействий модулей системы FORMS при пе-
КЛАВИАТУРА
ПОСТРОЧНО-ПЕЧАТАЮЩЕЕ УСТРОЙСТВО
УПРАВЛЕНИЕ-ФИЗИЧЕСКИМ- ДИСПЛЕЕМ
КЛАВИАТУРА
ПОСТРОЧНО-ПЕЧАТАЮЩЕЕ УСТРОЙСТВО
УПРАВЛЕНИЕ-ФИЗИЧЕСКИМ- ДИСПЛЕЕМ
чати и редактировании.
Условные обозначения: KEYBOARD LINE-PRINTER PHISICAL-DISPLAY -MANAGEMENT PUT-STROKE RECOGNIZE
НАЖАТИЕ КЛАВИШИ РАСПОЗНАТЬ
Указывает на то.Указывает на то.Защита на случай отсутствияЗащита на случай отсутствия(б) Внутренний структурный граф задачи дешифратора событий »(б) Внутренний структурный граф задачи дешифратора событий »Рис. 4.25 (продолжение).Рис. 4.25 (продолжение).
Указывает на то.
Указывает на то.
Защита на случай отсутствия
Защита на случай отсутствия
(б) Внутренний структурный граф задачи дешифратора событий »
(б) Внутренний структурный граф задачи дешифратора событий »
Рис. 4.25 (продолжение).
Рис. 4.25 (продолжение).
событий в системе, которое может оказаться несостоятельным в результате последующих изменений технических требований или проектных решений по системе. При введении задачи-курьера как посредника между клавиатурой и дешифратором событий невозможна никакая излишняя вынужденная задержка в работе печатающего устройства при наличии доступных для печати строк, поскольку задача дешифратора событий никогда не будет находиться в состоянии ожидания каких-либо других событий в то время, когда задача печатающего устройства запрашивает очередные строки.
Отметим, что на рис. 4.25, а показана не полная структура системы, а лишь ее часть, связанная с верхним уровнем взаимодействия операций редактирования и печати. Характер этой структуры очевиден из ранее рассмотренных схем и обсуждений, и привести ее для получения полной картины не составляло бы никакого труда. Однако заметим, что здесь мы имеем
task EVENT_DECODER is
entry PUT_STROKE (K : tn KEYSTROKE);
ВОСПРИНИМАЕТСЯ ВСЕГДА
entry MORE_LINES (N.M : out LINE_NUMBER; STATUS: out STATUS_TYPE);
ИСПОЛЬЗУЕТСЯ ДЛЯ СИГНАЛИЗАЦИИ ОБ ОКОНЧАНИИ ДЕЙСТВИЯ и для
ПОЛУЧЕНИЯ ОЧЕРЕДНЫХ СТРОК
ВОСПРИНИМАЕТСЯ ТОЛЬКО ПРИ НАЛИЧИИ ГОТОВЫХ СТРОК )ОБ ОСОБОМ СЛУЧАЕ КОНЦА ДОКУМЕНТА ИЗВЕЩАЕТ СИГНАЛ —■— О СОСТОЯНИИ
end EVENT_DECODER;
task body EVENTDECODER is
type STATUS_TYPE is (MORE, NO_MORE, DONE);
RESULT: STATUS_TYPE : = DONE;
STATUS: STATUS_TYPE : = DONE;
N.M: ...
ЗДЕСЬ РАСПОЛАГАЮТСЯ ВНУТРЕННИЕ обьявления пакета loop select
' accept PUT_STROKE (К : in ...)
do RECOGNIZER.RECOGNIZE (K, RESULT); end;
or
when RESULT/ = DONE = >
accept MORE_LINES (N.M : out...; STATUS : OUT,,.);
do STATUS : = RESULT;
N : = . . .;
M : = ..,;
if RESULT = NO_MORE then
PROCESSOR.DONE;
RESULT : = DONE; end if;
end;
end’ select;
end loop;
end EVENT-DECODER;
(e) Скелет программы на языке Ада,.
Рис. 4.25 (продолжение).
дело с одним из частных случаев, когда полные структурные схемы менее информативны, чем ряд фрагментов, показывающих, как части системы взаимодействуют в конкретных целях. Нередко бывает желательно сфокусировать внимание на отдельном пакете или задаче и всех взаимосвязях с другими пакетами или задачами, не касаясь взаимодействий последних друг с другом.
Обратимся теперь к внутренним деталям задачи дешифратора событий (EVENT-DECODER). На рис. 4.25,6 приведена одна из возможных структур, содержащая вложенные пакеты для реализации модулей распознавателя и процессора команд. Управляющим модулем является главный цикл задачи.
Скелет программы на языке Ада представлен на рис. 4.25, в.
Оценка принятых проектных решений
Можно достичь более простого взаимодействия пакета редактирования поля с внешней средой, если внутри этого пакета будет сохраняться контекст поля, под которым понимается физическое положение и размеры поля на экране наряду со всеми его необходимыми атрибутами. На рис. 4.26 иллюстрируется этот подход. Он предоставляет заманчивую возможность расширения операций редактирования путем включения
Ввести символ в физический дисплей и переместить курсорВвести символ в физический дисплей и переместить курсорРис. 4.26. Альтернативный принцип построения пакета редактирования поля.Рис. 4.26. Альтернативный принцип построения пакета редактирования поля.Условные обозначения: UPDATE — CONTEX1 BOUNDARY — CHECK FIELD—CONTEXTУсловные обозначения: UPDATE — CONTEX1 BOUNDARY — CHECK FIELD—CONTEXTОБНОВЛЕНИЕ — КОНТЕКСТА ПРОВЕРКА — ГРАНИЦ КОНТЕКСТ — ПОЛЯОБНОВЛЕНИЕ — КОНТЕКСТА ПРОВЕРКА — ГРАНИЦ КОНТЕКСТ — ПОЛЯ
Ввести символ в физический дисплей и переместить курсор
Ввести символ в физический дисплей и переместить курсор
Рис. 4.26. Альтернативный принцип построения пакета редактирования поля.
Рис. 4.26. Альтернативный принцип построения пакета редактирования поля.
Условные обозначения: UPDATE — CONTEX1 BOUNDARY — CHECK FIELD—CONTEXT
Условные обозначения: UPDATE — CONTEX1 BOUNDARY — CHECK FIELD—CONTEXT
ОБНОВЛЕНИЕ — КОНТЕКСТА ПРОВЕРКА — ГРАНИЦ КОНТЕКСТ — ПОЛЯ
ОБНОВЛЕНИЕ — КОНТЕКСТА ПРОВЕРКА — ГРАНИЦ КОНТЕКСТ — ПОЛЯ
полного набора функций редактирования полей, аналогичных функциям, связанным с постраничной обработкой текстов.
Однако, прежде чем ухватиться за эту заманчивую возможность, рассмотрим рис. 4.27, на котором иллюстрируется принцип управления курсором, аналогичный применяемому во многих текстовых процессорах, но отличный от рассматривавшегося нами до сих пор. Этот принцип обеспечивает физическое перемещение курсора по всему экрану независимо от текущего логического контекста; факт допустимости или недопустимости операций, связанных с новым положением курсора, устанавли-
вается в рамках пакета управления логическим дисплеем. Такой подход трудно согласовать с принципом, при котором все логические операции над полем, в том числе и перемещение курсора внутри поля, осуществляются под управлением пакета редактирования поля, как предполагается на рис. 4.26.
Особый интерес при разработке проектов, в которых предусматривается взаимодействие системы с оператором, представляет возможность включения новых форм взаимодействия без
Рис. 4.27. ИПГ, показывающий смешанные операции перемещения логического и физического курсора.
внесения существенных изменений в проектные решения. Если же все-таки потребуются какие-либо изменения, то важно прежде всего получить ответы на три вопроса:
Можно ли ограничиться изменениями таблиц?
Можно ли ограничиться изменениями программы и таблиц в одном модуле?
Требуется ли наряду с модификацией модулей изменять взаимодействия между ними?
В системе FORMS изменения могут оказаться необходимыми из-за целого ряда недостатков этой системы, к числу которых относятся:
— отсутствие средств обработки команд, набираемых путем нажатия нескольких клавиш, и средств отображения вводимых команд на экране;
— отсутствие надлежащих средств для выполнения вставок в рамках поля;
— отсутствие возможности управления печатью со стороны оператора;
— невозможность возврата к предыдущему полю после перехода к следующему без повторного редактирования всей формы;
— отсутствие возможности хранения таблиц описания форм в основной или вспомогательной памяти.
В связи с отмеченными недостатками правомерно задать вопрос: можно ли их устранить в рассматриваемом проекте без особых трудностей?
Что касается обработки многоклавишных команд, то здесь не возникает никаких проблем. Эти команды могут быть включены в число распознаваемых путем добавления в дешифратор событий блока распознавания последовательности сигналов нажатия клавиш, которая может представлять собой как цепочку символов, образующих команду, так и. последовательность команд. Не должно быть затруднений и с отображением набираемых команд на экране, поскольку в системе предусмотрено воздействие индивидуальных сигналов клавиатуры на экран дисплея.
Изменения, обеспечивающие автоматический сдвиг текста вправо или влево при вставлении или удалении символа, могут ограничиваться внутренней логикой пакета редактора поля (FIELD-EDIT) и, следовательно, могут быть внесены достаточно просто. Интерфейс этого пакета не нужно изменять даже при условии, что запросы вставок или удалений будут передаваться в качестве параметров процедуры ENTER-CHAR в виде кодов соответствующих символов.
Возможность управления печатью со стороны оператора й просмотр им полей в произвольном порядке легко реализовать ценой отказа от параллельного редактирования и печати одной и той же формы. Логика данного конкретного проекта основывается на требовании, чтобы строки, находящиеся в верхней части страницы, могли печататься в то время, когда поля в нижней ее части все еще редактируются. Чтобы осуществить возможность заполнения окон оператором в произвольном порядке, следует, таким образом, отказаться от одновременного редактирования и печати одной и той же формы. Структура нашей системы такова, что сделать это несложно. Достаточно просто модифицировать для каждой формы таблицу ее описания так, чтобы все строки для печати освобождало только поле, расположенное в правом нижнем углу бланка. Именно с этой целью можно даже создать специальное небольшое поле, разрешающее печать. Что касается произвольного порядка доступа к полям, следовало бы переопределить команду NEXTFIELD так, чтобы она включала в качестве параметра номер поля, а процедура NEXT-FIELD в пакете управления логиче-
ским дисплеем учитывала этот параметр. В остальном система осталась бы без изменений.
Другой путь обеспечения раздельной печати, который потребовал бы некоторой модификации системы, заключается в добавлении команды печати. Эта команда печати должна была бы распознаваться дешифратором событий, и тогда печать производилась бы в случае распознавания именно этой команды, а не по факту выхода из поля, разрешающего печать формы. В отличие от рис. 4.25 задача дешифратора событий в данном случае не должна получать сведения о диапазоне номеров строк страницы в качестве параметра обращения к процедуре NEXT-FIELD. Вместе с тем не должно быть внесено никаких изменений в способ организации взаимодействия задачи построчно-печатающего устройства с задачей дешифратора событий. При получении команды печати (в которой в качестве параметра может присутствовать диапазон номеров строк страницы) задача дешифратора событий должна, как и прежде, просто пересылать диапазон номеров строк страницы в качестве параметра задаче построчно-печатающего устройства.
Заметим, что здесь невозможен никакой конфликт между редактированием и печатью ни в первоначальной системе, ни в любом из рассмотренных вариантов, поскольку такие конфликты предотвращает дешифратор событий. В силу этого обстоятельства решение объявить управление физическим дисплеем пассивным пакетом оказывается оправданным, как и решение пересылать печатающему устройству номера строк, а не сами строки. Отметим, однако, что при этом в случае добавления в систему новых задач возможно снижение надежности.
Довольно просто также обеспечить хранение таблиц описаний форм во вспомогательной памяти. Для этого следовало бы изменить процедуру NEW-FORM в пакете управления логическим дисплеем так, чтобы для получения таблицы описания формы осуществлялся доступ к файловой системе, а не происходило простое обращение непосредственно к таблицам, уже хранящимся в основной памяти. В остальном часть системы, связанная с редактированием, остается без изменений.
4.6. Пример проектирования системы DIALOGUE
(ДИАЛОГ)
В качестве последнего примера этой главы рассмотрим проект системы, обеспечивающей взаимодействие операторов, находящихся в географически рассредоточенных пунктах, с помощью видеоэкранов их рабочих станций, которые используются
для подготовки и приема сообщений. Этот пример порождает новую интересную проблему состязания за обладание ресурсами (в данном случае экраном) между равноправными партнерами, а не между главным и подчиненным процессами, как в случае системы FORMS. В системе FORMS состязание за обладание общим ресурсом (памятью видеодисплея) происходило между главной задачей переднего плана и подчиненной фоновой задачей, работа которой явно инициировалась задачей переднего плана. Новой особенностью системы DIALOGUE является
Специальные функциональные клавиши:
RESERVE - зарезервировать экран
RELEASE -освободить экран (и очистить его)
SEND-послать сообщзние,высвеченное
на экране, освободить экран
Рис. 4.28. Заключительный пример проектирования — система DIALOGUE.
то, что операторы, находящиеся на большом расстоянии один от другого, взаимодействуют на основе принципа равноправия. В одной и той же рабочей станции, расположенной в конкретном пункте, и локальный оператор, и дистанционный оператор будут иметь собственную обслуживающую задачу, и соответственно на эти задачи тоже должен распространяться принцип равноправия. Такое равноправное состязание за обладание общими ресурсами выдвигает ряд новых проблем проектирования.
На рис. 4.28 приведена самая общая схема системы DIALOGUE. Человек-оператор на любом из концов сети передачи данных имеет возможность вводить команды и информацию с помощью клавиатуры, на которой имеются три специальные функциональные клавиши RESERVE, RELEASE и SEND. Функциональная клавиша RESERVE обеспечивает резервирование экрана для подготовки сообщения. Функциональная клавиша RELEASE освобождает экран и очищает его, когда оператор решает прекратить подготовку незаконченного сообщения и не
Данные, подлежащие
e.g., RESERVEПредполагается
Еосвобождение экрана
Нпосле того, как
Lсообщение будет скопировано
RELEASEДЛЯ передачи
RESERVE
Н Е
L L О SEND RESERVE G
О
О■
D.■
В Y
Е SEND
Рис, 4.29. Схема конечного автомата, показывающая допустимые последовательности нажатий клавиш в системе DIALOGUE.
передавать его или освободить экран после прочтения сообщения, принятого от дистанционного оператора. Функциональная клавиша SEND используется для отправки записанного на экране сообщения дистанционному оператору с последующим освобождением и очисткой экрана. Сигналы от клавиатуры могут поступать также при нажатии любых буквенно-цифровых клавиш.
В этом примере мы не будем останавливаться на подробностях форматирования экрана или отображения на экране команд, а рассмотрим только последовательность осуществляемых взаимодействий. Мы не станем также касаться деталей организации связи в сетях передачи данных, а просто будем предполагать, что между двумя терминалами либо существует физическая связь, либо связь может быть каким-то образом установлена через общедоступную сеть передачи данных. Будем предполагать также, что имеется некоторое устройство для передачи текстового сообщения на подключенный в даН'
ный момент удаленный терминал и для приема от него текстового сообщения. Процесс проектирования подобной системы передачи сообщений рассматривается в гл. 6.
Наше основное внимание в данном примере направлено на проблему установления очередности событий в системе, чтобы избежать ошибок в последовательности обработки, как, например, в случае, когда подготовленное на локальном терминале сообщение подавляется поступившим от удаленного термина
ла еще до его отправления.
Весьма просто построить конечный автомат, реализующий правильную последовательность действий по резервированию, освобождению и пересылке сообщений с локального экрана. На рис. 4.29 представлен конечный автомат, обеспечивающий эти операции, и дан пример правильной последовательности сигналов клавиатуры. Заметим, что в данном конечном автомате неявно предполагается, что сообщения пересылаются с экрана
Сообщения
сообщения, ответы вывода на экран
Рис. 4.30. Схема разработки ИПГ системы DIALOGUE по принципу «от границ — внутрь»,
в систему передачи сообщений как единое целое. Однако правильная последовательность будет зависеть от событий, относящихся к удаленному терминалу; прежде чем включить их в схему конечного автомата, мы должны исследовать поток данных.
Поток данных
На рис. 4.30 представлен первый этап разработки информационного потокового графа для рассматриваемой системы, которая проектируется по принципу «от границ — внутрь». В каждой рабочей станции должны быть интерфейс клавиатуры, интерфейс экрана и интерфейс системы передачи сообщений. Двигаясь внутрь от этих границ проектируемой системы, мы легко обнаруживаем потребность в модуле управления событиями, который должен играть роль посредника между всеми функциями интерфейсов. Рассматривая внутреннюю структуру модуля, мы можем прийти к выводу о необходимости накопителя событий, который формирует из сигналов клавиатуры и входящих сообщений единый последовательный поток событий, а также дешифратора событий, который декодирует их и выполняет соответствующие действия. Необходимость преобразования потока событий к последовательной структуре возникает в связи с тем, что сообщения от удаленной станции поступают в непредсказуемые моменты времени и не контролируемые ни человеком-оператором, ни средствами интерфейса клавиатуры.
Состояния»
IDLE;ЭКРАН СВОБОДЕН
BUSY— LDC^U ЭКРАН ЗАРЕЗЕ РВИРОВАН.ДЛН ВВОДА
ЛОКАЛЬНОГО СООБЩЕНИЯ
BUSY .^ REMOTE: ЭКРАН ЗАРЕЗЕРВИРОВАН ДЛЯ ВЫВОДА 'ДИСТАНЦИОННОГО СООБЩЕНИЯ
Рис. 4.31. Раширенная схема конечного автомата, показывающая допустимые последовательности событий в системе DIALOGUE,
Используя идею потока событий, мы можем теперь определить расширенный конечный автомат, показывающий допустимые последовательности событий (рис. 4.31). В этом конечном автомате прежнее состояние BUSY (ЗАНЯТО) переименовано в BUSY-LOCAL (ЗАНЯТО_В_ЛОКАЛЬНОМ_РЕЖИМЕ) и добавлено новое состояние BUSY-REMOTE (ЗАНЯТО_В_ДИ- СТАНЦИОННОМ-РЕЖИМЕ). В состояние BUSY-REMOTE можно перейти только из состояния IDLE (ОЖИДАНИЕ), что предотвращает наложение на экране одного сообщения на другое.
Структура системы
Исходя из ИНГ, представленного на рис. 4.30, и схемы конечного автомата, упорядочивающего поток событий (рис. 4.31), мы можем приступить к разработке структурного графа проектируемой системы.
На рис. 4.32 показаны в исходном виде структура системы DIALOGUE и программа на языке Ада. По тем же причинам, которые обсуждались при проектировании системы FORMS в разд. 4.5.4, эта структура включает две задачи-курьеры (по одной для каждого типа событий) во избежание возникновения каких-либо затруднений, связанных с чрезмерной задержкой при распознавании событий. Эти задачи обращаются к входам PUT-STROKE (ПРИЕМ-СИГНАЛА) и PUT-MESSAGE (ПРИЕМ-СООБЩЕНИЯ) задачи дешифратора событий.
Реакция на обращение к входу PUT-STROKE не связана ни с какими условиями, что же касается вызова входа PUT- MESSAGE, то он принимается только тогда, когда конечный автомат находится в состоянии ожидания. Поскольку для каждого из этих входов имеется лишь одна задача-курьер, соответствующие входные очереди не могут содержать более одного сигнала от клавиатуры или более одного сообщения. Таким образом, если во время ожидания задачами-курьерами приема их вызовов дешифратором событий возможно поступление нескольких сигналов от клавиатуры и нескольких сообщений, они должны ставиться в очередь к задаче обработки прерываний от клавиатуры или к интерфейсу системы передачи сообщений. В первом случае это может быть достигнуто путем введения буфера опережающего ввода, как показано на рисунке. Мы не будем здесь касаться внутренних деталей системы передачи сообщений, однако для функционирования системы, представленной на рис. 4.32, несущественно, будет ли система передачи сообщений иметь внутри подобную буферизацию.
Как показано на рис. 4.32, б, конечный автомат должен быть в явном виде представлен операторами в задаче дешифратора событий. Если же ради обеспечения модульности
конструкции желательно иметь таблично управляемый конечный автомат, то последовательность событий должна быть доступной внутри задачи дешифратора событий. Из этого следует необходимость удаления буфера опережающего ввода из задачи обработки прерываний от клавиатуры, замены входов PUT- STROKE и PUT-MESSAGE одним входом PUT-EVENT и добавления внутрь задачи дешифратора событий информационной структуры накопителя событий.
Результат этих преобразований (представленный только структурным графом) показан на рис. 4.33. Теперь, поскольку конечный автомат работает в прямом соответствии с последовательностью событий, он может быть полностью таблично управляемым. Накопитель событий определен как внутренний пакет задачи дешифратора событий с отдельными интерфейсными процедурами для передачи и приема сигналов нажатия клавиш, сигналов сообщений или другого очередного события любого типа.
Оценка проектных решений
Чтобы проектные решения, принятые до сих пор, не показались слишком простыми, рассмотрим другой подход, который на первый взгляд кажется весьма естественным, но в логическом плане является более сложным. Этот альтернативный
(а) Структурный граф.
task EVENT_DECODER is
entry PUT STROKE (K : in ....);
— ВОСПРИНИМАЕТСЯ ВСЕГДА
entry PUT_JVISG (M : in .,.);
— ВОСПРИНИМАЕТСЯ ТОЛЬКО ПРИ простоях end EVENT_DECODER;
task body EVENT_DECODER is
S : STATE : = IDLE;
loop
select
accept PUT_STROKE (K :...);
do
case S is
when IDLE = >
if К = RESERVE then S : = BUSY_LOCAL;
else RING_BELL; end if;
When BUSY_LOCAL = > case К is
When RELEASE = > S : = IDLE;
SCREEN.CLEAR;
when SEND = > S : = IDLE;
MESS.SEND (...);
SCREEN.CLEAR;
when in LEGAL_CHAR = >
SCREEN.WRITE (K);
When OTHERS = >
RING_BELL;
end case;
when BUSY_REMOTE = >if К = RELEASE then ’
S : = IDLE;
SCREEN.CLEAR;
else RING_BELL; end if;
end case;
end;
•or
when S = IDLE = >
accept PUT_MSG (M;., .);
do S: = BUSY_REMOTE;
SCREEN.DISPLAY (M);
end;
. end select;
end loop;
end EVENT_DECODER;
Скелет программы на языке Ада.,
Рис. 4.32 Накопитель событий реализуется неявно путем организации входных очередей к задаче дешифратора событий.
Рис. 4.33. Накопитель событий реализуется в теле задачи дешифратора событий.
подход (рис. 4.34) допускает свободную конкуренцию за обладание экраном между дешифратором клавиатуры и системой передачи сообщений и не предполагает наличия промежуточного параллельно-последовательного преобразователя потока событий по типу предыдущего проекта. В данном случае планировщик экрана управляет доступом к экрану, не имея никаких сведений о целях поступающих запросов. Из-за непредсказуемости моментов их поступления любая из конкурирующих сторон (дешифратор клавиатуры или система передачи сообщений) может оказаться вынужденной ожидать разрешения доступа к экрану. Возникающая при этом подходе трудность заключается в том, что указанные два конкурента используют экран асимметрично. Система передачи сообщений только запрашивает доступ к экрану для вывода поступающих сообщений, но не может сама освободить экран; это способен сделать только дешифратор клавиатуры, после освобождения экрана оператором. В результате возникает неприятная асимметрия операций обработки событий, связанных с клавиатурой и сообщениями, которая полностью отсутствовала при прежнем подходе. Эта асимметрия увеличивает сложность системы.
Здесь налицо один общий принцип: когда за обладание ресурсами состязаются несколько операций, порожденных человеком-оператором и элементами системы, координация этих one-
Рис. 4.34. Информационный поток в системе DIALOGUE, имеющий более сложную структуру.
раций должна быть централизованной, а не распределенной. В противном случае может потребоваться сложная взаимосвязь между операциями, и принцип модульности человеко-машинного интерфейса окажется нарушенным.
В рассмотренном проекте мы позволили себе совершенно не задумываться над вопросами буферизации сообщений и обеспечения интерфейса сети передачи данных. Этим вопросам будет посвящена гл. 6.
4.7. Заключение
В этой главе была сделана попытка проиллюстрировать на различных примерах стратегии и методы проектирования, сам процесс проектирования и связанные с ним технические вопросы.
Мы готовы теперь к изучению части III, в которой основные проблемы части II исследуются более детально.
Часть III
Анализ проблем логического проектирования
В этой части книги сначала рассматриваются более подробно некоторые свойства языка Ада, влияющие на выбор проектных решений, на примерах части II с привлечением ряда новых примеров. Далее излагаются вопросы модульности, надежности и структурирования проектируемых систем, иллюстрируемые проектом подсистемы передачи данных СОММ, которая предназначена для использования в системе DIALOGUE. В заключение рассматриваются в общем виде проблемы проектирования многоуровневых параллельных систем на примере разработки, реализующей протокол X. 25 для сетей с коммутацией пакетов.
Глава 5
Дополнительные сведения о языке Ада
Введение .
В этой главе мы рассмотрим ряд аспектов языка Ада, которые были лишь вскользь затронуты в предыдущих главах. Здесь прежде всего будет обращено внимание на организацию и взаимодействие активных модулей, а именно задач или активных пакетов. Цель этой главы — обсудить возможный круг потребностей разработчика и способы их описания с помощью языка Ада.
В разд. 5.2 рассматриваются вопросы, связанные с идентификаторами и пулами задач, динамическим доступом и порождением задач на примере пакета BANK из гл. 3, а также проблема присваивания имен идентификаторам.
Раздел 5.3 посвящен вопросам, связанным со структурами взаимодействий задач. Определяются и исследуются линейные и нелинейные структуры на примере управления потоками данных, рассматриваются проблемы синхронизации процессов, возникающие при взаимодействии считывающих и записывающих
задач, а также вопросы размещения пулов задач. Попутно иллюстрируются и решаются проблемы информационного «голода» задач и их состязания за обладание ресурсами.
В разд. 5.4 вновь рассматриваются процедуры регистрации событий с целью охвата исключительных ситуаций. Как показано в этом разделе, последние существенно меняют представление о структуре системы, вследствие чего ими нужно пользоваться весьма аккуратно и умеренно.
Раздел 5.5 посвящен вопросам обнаружения и всестороннего контроля случаев неправильного выполнения модулей. Здесь делается попытка ответить на целый ряд вопросов. Можно ли создать такое тестовое программное обеспечение, которое позволило бы обнаруживать неправильное поведение, например, задач и активных пакетов? Когда следует использовать межзадачные протоколы для защиты от неправильного выполнения других задач? Какой должна быть организация модулей при проектировании распределенных вычислительных систем с потенциально ненадежными связями и узлами?
В разд. 5.6 рассматриваются вопросы конструирования систем, вследствие чего язык Ада характеризуется здесь как средство структурного проектирования, обеспечивающее реализацию модульного принципа построения систем. Анализируются особенности процедур динамического введения новых модулей или реконфигурации старых и делается попытка ответить на вопрос: как должен разработчик трактовать пакеты и задачи в аспекте конструирования систем на их основе, а не просто с точки зрения методологии структурного проектирования? Именно в этом разделе читателю предстоит столкнуться с целым рядом существенных ограничений языка Ада.
Вопросы динамического доступа
и порождения задач
. В этой части мы исследуем некоторые важные вопросы динамического взаимодействия и порождения задач, которые если и рассматривались в предыдущих главах, то весьма бегло. Например: как можно присваивать идентификаторы задачам и делать эти идентификаторы общедоступными в динамическом режиме (скажем, для того чтобы позволить задачам-потребителям обращаться к произвольным элементам пула заранее неизвестных задач или чтобы дать возможность служебной задаче в свою очередь обращаться к необъявленным предварительно задачам-потребителям)? До сих пор предполагалось, что все задачи хорошо известны, и поэтому их идентификаторы явно указаны в операторах вызова. В связи с этим возникает другой
вопрос: как активные пакеты, реализующие пулы задач, могут защищаться от неправильного использования динамически присвоенных идентификаторов? А отсюда следует очередной вопрос: как по мере необходимости динамически создавать элементы пулов задач?
В языке Ада существует стандартный механизм для идентичных задач, который дает возможность определять задачи как типы. Это позволяет, например, в банковском пакете BANK из гл. 3 определить единственную задачу TELLER-TYPE (КАССИР). Отдельные экземпляры этой задачи могут порождаться различными способами, простейший из которых состоит в том, чтобы определить TELLER-TYPE как соответствующее число задач. Имена этих задач могут затем использоваться в операторах обращения к входам. Это менее громоздкий метод по сравнению с использовавшимся в гл. 3, где каждая задача- кассир определялась отдельно и имела собственные спецификацию и тело. Однако в этом случае возникают проблемы установления идентичности задач, относимых к одному типу, и несколько позже мы в этом убедимся.
Косвенный доступ к произвольным элементам пулов задач
Прямое использование имен произвольных типов задач — не всегда лучший способ идентификации их различных экземпляров в прикладных системах. Часто бывает удобнее различать элементы пулов задач по идентификаторам, которые зависят от конкретной сферы применения. В случае банковских операций это могут быть, например, номера кассовых окошек в протоколах связи, номера абонентов или номера устройств в операциях ввода-вывода. Подобный метод присваивания проблемно-зависимых идентификаторов позволяет реализовывать механизм рандеву даже тогда, когда задачи скрыты в активных пакетах.
Обратимся опять к пакету BANK, сохранив механизм использования номеров окошек, но используя на этот раз всего один тип задач, решаемых кассирами. Механизм назначения номеров окошек порождает в данном случае проблему отождествления кассиров, так как определение тела задачи теперь, очевидно, не может включать статической инициализации номера окошка. В связи с этим каждый кассир должен как-то узнавать номер своего окошка в динамическом режиме, для чего существуют две возможности: либо диспетчер вызывает кассира, либо кассир вызывает диспетчера.
Первая возможность проиллюстрирована на рис. 5.1, а. Задачи-кассиры здесь являются элементами массива. В процессе инициализации диспетчер вызывает каждую задачу этого массива, указывая свое имя и индекс последнего в спецификаторе
оператора вызова, и пересылает определенной задаче индекс конкретного массива для использования этого индекса в качестве номера окошка. Позже, в процедуре REQUEST-SERVICE (ОБСЛУЖИВАНИЕ-ЗАПРОСА) переданный в нее задачей-потребителем номер окошка аналогичным образом обеспечивает вызов соответствующего кассира.
Вторая возможность, заключающаяся в вызове диспетчера кассиром, более сложна для реализации. На рис. 5.1,6 показано, как кассир вначале обращается к диспетчеру для получения номера своего окошка. Вслед за этим всякий раз, когда кассир свободен, он передает диспетчеру собственный номер окошка через единственный вход READY (ГОТОВ). Но теперь обслуживающая процедура REQUEST-SERVICE должна с помощью этого номера правильно найти соответствующую задачу. В данной ситуации эта процедура может просто организовывать вызовы кассиров до тех пор, пока не будет найден кассир с нужным номером окошка. Та же проблема может быть решена и более сложным способом — путем организации обращения каждого кассира к диспетчеру через собственный вход READY, с тем чтобы диспетчер формировал таблицу соответствия между номерами окошек и кассирами, которая впоследствии могла бы использоваться в процедуре REQUEST-SERVICE для определения нужного кассира.
Кассир может также сообщать диспетчеру вместе с номером окошка свой идентификатор. Но теперь круг, по которому мы шли, окончательно замкнулся, ибо возникает вопрос: как кассир узнает свой собственный идентификатор? Этот вопрос рассматривается в подразд. 5.2.2 и 5.2.3.
Прямая динамическая связь между задачами
Рассмотрим ситуацию, когда вместо осуществления рандеву с неизвестными задачами через интерфейсные процедуры активных пакетов желательно реализовать прямой контакт между задачами. В этом случае значения идентификаторов, которые явно не могут быть указаны в операторах вызова, должны передаваться между задачами. Такой подход может понадобиться в случае, если клиентам банка нужно прямо обратиться к кассирам или, наоборот, кассирам — к клиентам, например когда банку требуется некоторое время для совершения скрытых фоновых операций текущей сделки, и в течение этого времени кассир имеет возможность обслужить других клиентов.
Возможность прямого вызова задачи с помощью сообщаемого в динамическом режиме значения идентификатора задачи будем называть динамической связью, или динамическим доступом в противоположность статическому доступу, который
использовался во всех предыдущих примерах. На рис. 5.2 представлен структурный граф для случая динамического доступа. Задача А воспринимает идентификатор задачи В и обращается к ее входу, используя полученное значение в операторе вызова. В данном варианте отсутствует промежуточная процедура, которая «узнает» имя задачи по ее прикладному идентификатору (см. подразд. 5.2.1). Таким образом, к момен-
package body BANK is
ПОКАЗАНА ТОЛЬКО ИНИЦИАЛИЗАЦИЯ
task type TELLER_TYPE is
entry ASK (...);
entry NAME (Lin WICKET);
end TELLER_TYPE;
TELLER COUNTER: array (WICKET) of TELLE RETYPE;
task body DISPATCHER is
WICKET;
for 1=1. , N loop
TELLER-COUNTER G).NAME(I);
end loop;
end DISPATCHER;"
"task bodyTELLER_TYPEiS
MY_NUMBER;WICKET;
''' accept NAME (MY„NUMBER: in WICKET);
end BANK;end BANK;end TELLER_TYPE;
end BANK;
end BANK;
^a) Путем приема вызова qt диспетчера..
package body BANK is
— ПОКАЗАНА ТОЛЬКО ИНИЦИАЛИЗАЦИЯ
task type TELLER-TYPE is
entry ASK (. ..);
endTELLER_TYPE;
TELLER!, TELLER2, TELLER3:TELLER_TYPE;
task body TELLER-TYPE is MY_NUMBER : WICKET; begin
DISPATCHER.GET (MY_NUMBER);
end TELLER-TYPE;
end BANK;
(б$ Путем вызова диспетчера..
Рис. 5.1. Способы идентификации элемента заданного пула.
ту программирования вызывающей задачи необходимо знать лишь тип вызываемой задачи, конкретное же значение идентификатора вызываемой задачи знать не обязательно.
С точки зрения проектировщика, подобные динамические связи были бы желательны между любыми типами модулей, однако, как показано на рисунке, динамические связи между процедурами или пакетами в языке Ада недопустимы.
Обратимся теперь опять к примеру BANK и посмотрим, как могут быть осуществлены динамические связи от клиентов к кассирам и от кассиров к клиентам. Первый вариант можно охарактеризовать как динамическую связь в прямом направлении при обслуживании клиентов, а второй вариант — как динамическую связь в обратном направлении,
Для удобства изложения на рис. 5.3, а изображен исходный пример пакета BANK (с номерами окошек) как иллюстрация статической связи в прямом направлении. .
На рис. 5.3, б приведен пример банковских операций с динамической связью в прямом направлении без использования номеров окошек. Здесь диспетчер сообщает клиенту параметр,
Значение, идентифицирующее задачу В,
разрешается использовать непосредственно
Й) Разрешенная.
Пакет АПакет А
Пакет А
Пакет А
Неразрешенная.
Рис. 5.2. Динамическая связь между модулями.
идентифицирующий кассира, а клиент непосредственно использует этот параметр в операторе вызова соответствующего кассира.
Какие же параметры могут применяться для идентификации кассиров при отсутствии номеров окошек, и как в тело задачи-кассира может быть сообщен идентификатор определенного кассира (а именно, того, чья задача выполняется в момент, когда требуется указать идентификатор)?
Простой (но, Увы> некорректный) метод реализации динамической связи заключается в том, что из тела задачи-кассира пересылается идентификатор типа для определения задачи, которой принадлежит выполняемое тело. Руководство по языку Ада позволяет надеяться на пригодность такого подхода, поскольку, согласно ему, идентификатор типа внутри тела задачи «указывает задачу, тело которой выполняется в данный момент». Этот некорректный подход иллюстрируется на рис. 5.4.
Приемлемый метод состоит в том, чтобы использовать параметры обращения. Мы отложим рассмотрение этих параметров
(6) Случай 2: динамическая связь,
Рис. 5.3. Система BANK: пример связи в прямом направлении. (Примечание. Номер окошка является переменной, которая неявна идентифицирует задачу кассира. Все вызовы кассиров явно указаны в операторе выбора CASE. Имя задачи кассира является переменной, которая явно идентифицирует задачу кассира. Эта переменная не может использоваться как символьный идентификатор задачи в тексте программы. Оператор выбора CASE не требуется.)
до подразд. 5.2.3, но попутно отметим, что задача не получает автоматически информации о значении собственного параметра обращения. Оно должно быть передано этой задаче путем инициирования рандеву, как если бы ей сообщался номер окошка по типу примера на рис. 5.1, а.
- На рис. 5.5 представлена система BANK с динамической связью в обратном направлении. Здесь клиенты сами сообщают о себе банковской системе, чтобы кассиры имели
package BANK it
task type TELLER_TYPE is entry ASK (TRANSACTION : in T-TYPE;
RESULT: out R_TYPE);
(Идентификатор типа задачи Z* использован в теле пакета ^ [в качестве самоидентифициру Ующего параметра для х {указания задачи, процесс < выполнения которой . достиг тела пакета.Это неправильно,(Идентификатор типа задачи Z* использован в теле пакета ^ [в качестве самоидентифициру Ующего параметра для х {указания задачи, процесс < выполнения которой . достиг тела пакета.Это неправильно,end TELLER_TYPE; , procedure REQUEST-TELLER (NAME: out TELLER-TYPE) end BANK;
(Идентификатор типа задачи Z* использован в теле пакета ^ [в качестве самоидентифициру Ующего параметра для х {указания задачи, процесс < выполнения которой . достиг тела пакета.
Это неправильно,
(Идентификатор типа задачи Z* использован в теле пакета ^ [в качестве самоидентифициру Ующего параметра для х {указания задачи, процесс < выполнения которой . достиг тела пакета.
Это неправильно,
package body BANK is task body (teLLER TYPe) is loop
так как в качестве параметров могут пересылаться только значения переменных.так как в качестве параметров могут пересылаться только значения переменных.DISPATCHER.BEADY ( (tELLER TYPE)); accept ASK (.»,) do WORK; end; CLEAN_UP; end loop;1
так как в качестве параметров могут пересылаться только значения переменных.
так как в качестве параметров могут пересылаться только значения переменных.
end TELLER-TYPE;
TELLER1, TELLER2, TELLERS : TELLER-TYPE; task DISPATCHER is entryWAlT (NAME: out TELLER_TYPE); entry READY (NAME; inTELLER TYPE);
end DISPATCHER;
task body DISPATCHER is separate;
procedure REQUEST-TELLER (...) is " begin DISPATCHER.WAIT (NAME);•
end BANK;
Рис. 5.4. Простой, но некорректный способ самоидентификации задачи в системе BANK (случай 2).
Рис. 5.5. Система BANK. Динамическая связь в обратном направлении (случай 3). (Примечание. Имя клиента является переменной, которая прямо идентифицирует задачу клиента, Необходимо использовать переменную доступа.)Рис. 5.5. Система BANK. Динамическая связь в обратном направлении (случай 3). (Примечание. Имя клиента является переменной, которая прямо идентифицирует задачу клиента, Необходимо использовать переменную доступа.)
Рис. 5.5. Система BANK. Динамическая связь в обратном направлении (случай 3). (Примечание. Имя клиента является переменной, которая прямо идентифицирует задачу клиента, Необходимо использовать переменную доступа.)
Рис. 5.5. Система BANK. Динамическая связь в обратном направлении (случай 3). (Примечание. Имя клиента является переменной, которая прямо идентифицирует задачу клиента, Необходимо использовать переменную доступа.)
возможность вызвать их позже. Даже если этот подход и не ис
пользуется при первом контакте клиента с кассиром, он может пригодиться, для того чтобы через некоторое время после начала рандеву кассир передал результаты своей работы клиенту. Поскольку нельзя ожидать, что служебным пакетам будут заранее известны имена всех клиентов, динамическая связь является единственным разумным средством осуществления взаимодействия в обратном направлении.
Простой (но тоже некорректный) метод реализации динамической связи в обратном направлении ■ заключается в том,
task CUSTOMER isentry REPLY (RESULT: in R_TYPE>> end CUSTOMER;task body(CUSTOMER)iskbegin 1task CUSTOMER isentry REPLY (RESULT: in R_TYPE>> end CUSTOMER;task body(CUSTOMER)iskbegin 1I Идентификатор задачи \/^ использован в теле пакета ''в качестве самоидентифицируйi ющего параметра.s
task CUSTOMER is
entry REPLY (RESULT: in R_TYPE>> end CUSTOMER;
task body(CUSTOMER)isk
begin 1
task CUSTOMER is
entry REPLY (RESULT: in R_TYPE>> end CUSTOMER;
task body(CUSTOMER)isk
begin 1
Это неправильно, так какв качестве параметров могут .пересылаться толькоу
значения переменных.
BANK.REOUEST_SERVICeT(cUSTOMER,') TRANSACTION);
accept REPLY (RESULT) do .,. end;
end loop;
end CUSTOMER;
Рис. 5.6. Простой, но некорректный способ идентификации задачи в системе BANK (случай 3).
что из тела задачи-клиента диспетчеру банка передается идентификатор задачи (рис. 5.6). Приемлемый метод будет описан в подразд. 5.2.3; суть его заключается в использовании параметров обращения.
Проблема определения значений идентификаторов характерна не только для таких пулов задач, как банковский пакет. Рассмотрим для примера пакет MAILROOM (ПОЧТОВОЕ- ОТДЕЛЕНИЕ), который позволяет одним задачам пересылать сообщения для других, пользуясь их именами, а также получать. сообщения на свое имя. Один из возможных способов реализации подобных действий заключается в том, чтобы задача-потребитель передавала свое собственное имя в качестве параметра вызова RCVE (ПОЛУЧИТЬ), а затем просто ожидала ответа на этот вызов до тех пор, пока на указанное имя не поступит сообщение. Безусловно, задача-потребитель может не ждать сама, а «поручить» это задаче-курьеру. Недостаток предложенной процедуры реализации ожидания состоит в том, что требуется специальная дисциплина обслуживания, поскольку определенная задача-потребитель должна стоять вместе с другими задачами во внутренней входной очереди, организованной по принципу FIFO («первым пришел — первым
обслужен»), а активизировать эту задачу нужно будет не во всех случаях, когда приходит почта, а только при поступлении корреспонденции на имя конкретного клиента. Как было выяснено в гл. 3, реализация специальной дисциплины обслуживания с использованием параметров вызова в языке Ада весьма затруднительна. Обойти эти трудности можно, если предоставить каждому клиенту «почтового отделения» свой собственный внутренний вход в задачу пакета MAILROOM. Очевидно, что
Рис. 5.7. Динамическая взаимосвязь в обратном направлении при получении почты в системе «почтовое отделение».
это нежелательно в тех случаях, когда пакет MAILROOM должен обслуживать множество задач-потребителей с заранее неизвестными именами.
Рассмотренная ситуация является примером, когда желательна динамическая связь в обратном направлении. Вместо того чтобы организовывать внутреннюю входную очередь к процедуре RCVE, можно использовать эту процедуру для передачи параметров вызова пакету MAILROOM. Если в данный момент для вызывающей задачи корреспонденции нет, то она может выполнять свои собственные действия до тех пор, пока опять не окажется готовой к получению сообщений. Для этого она должна активизировать оператор приема, принадлежащий входу, к которому обратился пакет MAILROOM, когда поступит соответствующая «корреспонденция».
Такой способ реализации взаимодействий иллюстрируется на рис. 5.7. Единственное, за чем здесь нужно следить, это чтобы задачи почтового пакета (который, разумеется, представляет собой активный пакет) не заставляли задачи-потре-
бители ждать приема вызовов GIVE (ВЫДАЧА) и тем самым не задерживали других клиентов, желающих отослать или получить почту.
Один из возможных принципов устранения указанной задержки заключается в том, чтобы обязать клиентов быть готовыми к принятию вызова GIVE сразу после передачи ими вызова ROVE почтовому пакету. В этом случае вызов процедуры
Рис. 5.8. Статическая взаимосвязь в прямом направлении при получении почты в системе «почтовое отделение».
ROVE удобен лишь для получения только одного почтового отправления.
Другой метод основан на использовании вызова RCVE для регистрации клиентов при условии, что в почтовом пакете много почтовых отправлений и имеется пул задач-курьеров, которые доставляют почту клиентам по требованию. В данном случае проблема ожидания исчезает, если имеется достаточно большой пул задач-курьеров, способный обслужить всех пользователей, или если элементы пула создаются динамически по мере необходимости.
Единственной альтернативой динамической взаимосвязи является организация почтовых ящиков. Почтовые ящики похожи на окошки в примере BANK с той лишь разницей, что они могут использоваться для многократного взаимодействия с почтовым пакетом. Этот подход иллюстрируется на рис. 5.8. Клиенты могут абонировать и освобождать почтовые ящики, используя их идентификаторы для передачи и получения сообщений. Внутри почтового пакета идентификаторы почтовых ящиков могут быть использованы для индексирования элементов семейства входов. Таким образом, имея почтовый ящик,
каждый клиент может ждать адресованную ему корреспонденцию как бы в собственной входной очереди. Читателю предлагается самостоятельно написать программы для пакета MAILROOM.
Динамическое порождение задач
Поскольку задачи могут быть определены как типы, экземпляры задач имеют много общих свойств с переменными и, в частности, могут порождаться динамически подобно выделению памяти для размещения переменных:
путем объявления экземпляров определенных типов, порождаемых в динамике, например, локально в процедуре;
путем определения параметров доступа (указателей) для различных типов задач и порождения их конкретных экземпляров с использованием оператора NEW.
Пулы задач, подобные задачам-кассирам в пакете BANK, являются очевидной сферой применения метода динамического порождения задач. Действительно, почему бы не создавать экземпляры задач-кассиров только тогда, когда появляются клиенты, которых нужно обслужить, экономя тем самым во все остальное время память, отведенную под таблицы описателей задач и стеки? Этот вопрос касается в основном эффективности реализации и поэтому выходит на другой логический уровень по сравнению с вопросами проектирования, связанными с организацией динамических связей.
Пример динамического порождения задач по мере возникновения надобности в них (для системы BANK) представлен на рис. 5.9. Заметим, что тело задачи TELLER-TYPE не содержит цикла, вследствие чего каждый экземпляр задачи существует лишь то время, в течение которого он работает. В целях упрощения в этом примере не наложено никаких ограничений на количество порождаемых задач-кассиров.
Более важно в аспекте проблем проектирования рассмотреть затронутый выше вопрос о том, что для обеспечения динамической связи задач должны использоваться их параметры доступа. При таком подходе необходимо динамическое порождение задач, но совсем не обязательно это должно делаться по требованию, как показано на рис. 5.9. Например, в системе BANK задачи кассиров могли бы порождаться диспетчером в процессе их запуска, а затем им могли бы передаваться их параметры доступа для дальнейшей «самоидентификации». Указанный принцип в логическом плане очень близок к использованию номеров окошек (рис. 5.1,ц), но только теперь номера окошек заменяются параметрами доступа.
package BANK is
procedure REQUEST-TELLER (NAME: out TELLER);,
task type TELLER_TYPE is
entry ASK (...);
end TELLER_TYPE:
type TELLER is access TELLER_TYPE;
end BANK;
package body BANK is
task body TELLER_TYPE is
accept ASK (. ,) do WORK end;
CLEAN_UP;
end TELLER_TYPE;
task DISPATCHER is
entry WAIT (NAME : out TELLER);
end DISPATCHER;
procedure REQUEST-TELLER (...) is
begin DISPATCHER.WAIT (NAME);
end;"
- - ЗАДАЧА:- ДИСПЕТЧЕР ПОРОЖДАЕТ НЕОГРА"
НИ ЧЕННОЕ ЧИСЛО ЗАДАЧ-КАССИРОВ
task body DISPATCHER is
NAME : TELLER-
begin
loop
accept WAIT.(NAME : out TELLER)
do NAME • = new TELLER—TYPE: end;
end LOOP;
end DISPATCHER;
end BANK;'
Рис. 5.9. Динамическое порождение задач по мере необходимости в системе BANK.
Проблема смешения идентификаторов
Термин «смешение» подразумевает одновременное существование множества экземпляров идентификаторов (которые связаны с конкретной прикладной системой или входят в число параметров доступа). Такая ситуация возникает в том случае, если идентификаторы не аннулируются явным образом, когда перестают быть нужными. Например, клиенты банковской системы не должны продолжать использовать старые номера окошек или прежние параметры доступа в задаче кассира после того, как взаимодействие с кассиром завершилось.
Один из способов предупреждения смешения идентификаторов в пакете BANK заключается в том, чтобы сделать идентификаторы задачи кассира одновременно входными и выходными параметрами процедуры запроса услуг кассиров, при
выходе из которой идентификатору присваивается недопустимое значение. При этом каждый вызов такой процедуры сопровождается проверкой допустимости значения идентификатора. В данном случае, конечно, требуется, чтобы идентификаторы представляли собой ограниченные приватные типы пакета BANK.
Описанный способ работы с идентификаторами номеров окошек представлен на рис. 5.10 и может быть использован как средство защиты в довольно простых (типа описанных
package BANK is
type WICKET, VALIDWICKET is limited private;
procedure REQUEST_TELLER (NAME: out VALID_WICKET);
procedure REQUEST_SERVICE (NAME: inout WICKET; RESULT:...); private
type WICKET is range 0,. 3;-0 ПРИ ИЗМЕНЕНИИ НАЗНАЧЕНИЙ
subtype VALID_WICKET is WICKET range 1 .. 3;
end BANK;'
package body BANK is
TELLER_COUNTER: array (VALID_WICKET) of TELLER_TYPE;
procedure REQUEST_SERVICE (NAME; inout WICKET; RESULT:... ); begin
TELLER_COUNTER (NAME).TELLER_TYPE.ASK (TRANSACTION, RESULT); NAME : = 0;
" exception
when CONSTRAINT_ERROR = > RESULT ; = INVALID_WICKET;
end REQUEST_SERVICE; end BANK;
Рис. 5.10. Программная защита от смешивания номеров окошек в системе BANK.
здесь) случаях возникновения проблемы смешения идентификаторов. Как увидим в гл. 6, в более общих ситуациях найти защиту не так просто.
Вопрос о том, как далеко следует заходить при защите от ошибок подобного рода, является дискуссионным. При проектировании пакета BANK мы заранее полагали, что клиенты будут осуществлять вызов кассиров только после того, как произойдет назначение кассиров клиентам; в противном случае кассиры будут обречены на бесконечное ожидание. Однако если считается возможным полагаться на клиентов в этом отношении, то можно довериться им и в том, что они не станут повторно использовать «старые» идентификаторы. Безусловно, можно путем перепроектирования банковского пакета защи-i
тпться от ошибочного вызова со стороны клиента. Существует, например, возможность, при которой одна и та же промежуточная процедура будет сначала обеспечивать запрос свободного кассира, а затем обращаться к нему за услугами. Другая возможность состоит в установлении лимита времени ожидания кассиром клиента.
5.3. Другие варианты структуры взаимодействия задач
Будем говорить, что задача имеет линейную структуру взаимодействий по отношению к другим задачам, если в ней отсутствует вложенность операторов приема и нет обращений к входам внутри критических секций принадлежащих ей операторов приема.
Во всех рассматривавшихся до сих пор примерах фигурировали линейные структуры взаимодействий. Тем не менее на практике возникают случаи, когда на первый взгляд может показаться (в особенности опытному программисту), что использовать такие структуры трудно или нецелесообразно. Цель данного раздела состоит в том, чтобы обосновать полезность применения линейных структур взаимодействий, показать на примере, как их можно развить, и предложить новую графическую нотацию для тех редких случаев, когда применение линейных структур оказывается неудобным.
Будут также рассмотрены вопросы представления конечных автоматов, информационного голодания задач и состязания задач за обладание ресурсами.
Использование линейных структур взаимодействий желательно по целому ряду причин.
Проектировщик может ясно и недвусмысленно установить все условия ожидания в аспекте защиты входов на уровне интерфейсов задач.
Процесс воплощения замыслов разработчика в программу на языке Ада может быть осуществлен почти механически, благодаря чему минимизируется вероятность возникновения ошибок и открывается заманчивая перспектива автоматизации программирования.
Внутренняя логика каждой задачи следует простой схеме «рандеву — обработка — ожидание», которая делает более легкими для понимания принципы организации всей системы в целом.
В этой части книги рассматриваются три примера, иллюстрирующие ключевые вопросы:
задача, которая осуществляет управление входящим потоком данных (подразд. 5.3.1);
задача, реализующая конечный автомат, который работает в соответствии со сложной специальной дисциплиной обслуживания (подразд. 5.3.2);
пул задач, которые явным образом абонируются и освобождаются задачами-потребителями (подразд. 5.3.3).
Особое внимание при рассмотрении этих примеров будет обращаться не просто на решение технических задач, а на выработку таких решений, которые помогут легче понять свойства заданных интерфейсов.
Пример управления потоком данных
Вопрос о том, как задача может осуществлять управление потоком данных, был кратко обсужден в гл. 3, где во всех решениях использовалась линейная структура взаимодействий.
Рассмотрим теперь вариант нелинейной структуры взаимодействий для решения этой проблемы, отображенной в виде линейной структуры на рис. 5.11, а, где модуль никогда не ждет разрешения на передачу данных, а всегда получает его в результате обращения к входу SEND модуля В. Однако разработчику может потребоваться реализация иной схемы взаимодействий, для которой у нас пока нет рисунка, и захочет он это сделать, например, следующим образом. Пусть В выдает А кредит на передачу как выходной параметр входа SEND, а модуль А ждет получения кредита после приема его обращения к входу SEND, если сразу получить кредит невозможно (модуль может «выражать согласие» па ожидание, например, путем пересылки соответствующего значения служебного параметра в коде операции). Тогда, если А инициирует вызов В.SEND, используя выданный кредит, то вызов SEND будет принят, но текущее рандеву не прервется до тех пор, пока не появится возможность «открытия кредита». Эта возможность будет, по-видимому, тогда, когда какая-либо другая задача обратится к входу B.RCVE за получением элемента данных. Единственный способ организации внутренней логики модуля В, удовлетворяющий описанным требованиям, заключается в том, чтобы вызов входа RCVE производился при выполнении критической секции входа SEND, что, естественно, нарушает линейность структуры взаимодействий.
Мы полагаем, что в общем случае нелинейные структуры взаимодействий могут оказаться весьма сложными как с точки зрения интерфейса, так и в аспекте их внутренней логики. Поэтому, прежде чем представить новый рисунок, отображающий потребности разработчика в нелинейной структуре взаимодействий, рассмотрим сначала причины возникающих осложне-
(а) Структурный граф, в котором может быть реализована нелинейная структура взаимодействий,-(а) Структурный граф, в котором может быть реализована нелинейная структура взаимодействий,-(6) Линейная структура взаимодействий.(6) Линейная структура взаимодействий.(г) Нелинейная структура взаимодействий(г) Нелинейная структура взаимодействийРис. 5.11. Линейные и нелинейные структуры взаимодействий для примера управления потоком данных.Рис. 5.11. Линейные и нелинейные структуры взаимодействий для примера управления потоком данных.Обозначает вложенный оператор приема RCVE в крити* ческой секции входа SENDОбозначает вложенный оператор приема RCVE в крити* ческой секции входа SEND
(а) Структурный граф, в котором может быть реализована нелинейная структура взаимодействий,-
(а) Структурный граф, в котором может быть реализована нелинейная структура взаимодействий,-
(6) Линейная структура взаимодействий.
(6) Линейная структура взаимодействий.
(г) Нелинейная структура взаимодействий
(г) Нелинейная структура взаимодействий
Рис. 5.11. Линейные и нелинейные структуры взаимодействий для примера управления потоком данных.
Рис. 5.11. Линейные и нелинейные структуры взаимодействий для примера управления потоком данных.
Обозначает вложенный оператор приема RCVE в крити* ческой секции входа SEND
Обозначает вложенный оператор приема RCVE в крити* ческой секции входа SEND
ний, а затем покажем, как можно решить данную проблему без обращения к нелинейной структуре.
■ Что касается интерфейса, то нелинейная структура взаимодействий усложняет его потому, что описание интерфейса значительно труднее по сравнению с линейной структурой, в которой вызов либо всегда принимается, а затем немедленно
обрабатывается до конца, либо блокируется и не принимается до тех пор, пока не сможет быть обработан. Таким образом, простая маркировка защищенного входа точкой, обозначающей блокировку по условному ожиданию, теперь оказывается недостаточной для отображения характера интерфейса, поскольку условное ожидание выходного параметра вызова может иметь место даже в том случае, когда защитная блокировка отсутствует. Более того, теперь вызывающий модуль уже не может использовать такое простое средство защиты от увеличения времени ожидания, как синхронизированный вызов входа: как только вызов SEND принят, вызывающий модуль оказывается полностью во власти вызываемого модуля.
С точки зрения внутренней логики нелинейные структуры сложны из-за того, что требуется явно согласовывать те части программы, которые обрабатывают обращения к разным входам. Например, если к вызываемой задаче происходит большое количество обращений в пределах одного оператора отбора, то после приема вызова по одному из входов и в ожидании вызова по другому входу вызываемая задача блокирует все остальные входы до окончания начатого рандеву. Если, однако, блокирование всех входов недопустимо, то возникает необходимость использовать вложенный оператор отбора, который осуществлял бы переключение вложенных операторов приема. В результате программа чрезвычайно усложняется. В линейных же структурах взаимодействий связь между входами ограничена такими прямыми операциями, как установка и снятие предохранителей, а также проверка и обновление значений локальных переменных.
На структурном графе рис. 5.11,6 представлены условные обозначения линейных взаимодействий, которые предусматривают ожидание предоставления кредита уже после того, как был передан вызов. На рис. 5.11, в показано, как пользователь мог бы рассматривать такую структуру, если бы задача В находилась внутри активного пакета, что на практике вполне вероятно. Рис. 5.11,6 иллюстрирует двойное преимущество линейной структуры: во-первых, простоту операций обработки одиночного вызова и, во-вторых, четкость самой линейной структуры взаимодействий задач.
Если же, несмотря на высказанные соображения, разработчик все равно захочет воспользоваться нелинейной структурой, то он сможет это сделать так, как показано на рис. 5.11, г. Из рисунка видно, что завершение рандеву по входу SEND может быть отложено в зависимости от значения служебного параметра в коде операции и от возможности предоставления кредита, если поместить вход RCVE в критическую секцию оператора приема, принадлежащего входу SEND. Тогда рандеву по
входу SEND не завершится ранее рандеву по входу ROVE, которое скорее всего должно привести к выделению некоторого лимита времени на передачу элемента данных.
Решение этой проблемы с помощью нелинейной структуры, приведенной на рис. 5.11, г, не столь уж сложно в аспекте средств интерфейса. Однако в общем случае эта сложность возрастает из-за того, что к входам, присутствующим во вложенных операторах приема, могут происходить и непосредственные обращения в рамках реализации альтернатив отбора, и среди таких входов могут оказаться даже защищенные. Можно далее представить в наглядной форме вложенные операторы приема, относящиеся к одному и тому же входу, используемому в нескольких различных альтернативах отбора, когда такая структура будет охватывать не один, а сразу несколько выходов. Но мы пока не будем останавливаться на этом вопросе и вернемся к нему при рассмотрении двух последующих примеров.
Решение задачи синхронизации чтения и записи с использованием концепций конечных автоматов
Представления в виде конечных автоматов повсеместно используются при проектировании самых различных систем, имеющих вложенную структуру. Было бы желательно поэтому найти способ применения этих четких, непротиворечивых и универсальных концепций для записи программ на языке Ада с целью обеспечения удобства их проверки и повышения удобочитаемости. Этим же целям служит и использование линейной структуры взаимодействий.
В гл. 4 уже было рассмотрено несколько примеров того, как модули конечных автоматов естественным образом появляются в структуре системы в ходе ее проектирования. В частности, при разборе системы DIALOGUE (ДИАЛОГ) была проиллюстрирована реализация конечного автомата в рамках задачи с использованием линейной структуры взаимодействий, обращений к входам с целью регистрации событий и защитной блокировки входов для обеспечения задержки обработки событий до момента достижения определенных состояний. В системе DIALOGUE спосрб действий был очевидным и естественным. Однако в более сложном случае при реализации специальной дисциплины обслуживания возникают явные затруднения, которые рассматриваются ниже на примере решения задачи синхронизации процессов чтения и записи.
Наша цель в данном разделе — последовательно разобрать несколько вариантов этой задачи, отличающихся степенью общности, с использованием как линейных, так и нелинейных
Рис. 5.12. Пример синхронизации процессов чтения и записи (внешнее пред.- ставление).
структур взаимодействий и сделать на этой основе окончательный выбор (рис. 5.16), остановившись на варианте, который является одновременно и достаточно общим, и имеет линейную структуру. По ходу рассмотрения задачи мы поставим и решим целый ряд побочных вопросов.
Проблема синхронизации процессов чтения и записи," часто возникающая в параллельном программировании, уже решалась многими способами, которые достаточно широко освещены в литературе. Эта проблема возникает тогда, когда имеется общая основная или вспомогательная память, доступная нескольким задачам, одни из которых только считывают информацию, а другие ее обновляют. В общем случае потребность в записи и чтении может возникать в любое время, однако в каждый конкретный момент запись может быть разрешена только одной из задач. Пока выполняется операция записи, все остальные задачи не имеют доступа к данным ни для чтения, ни для записи. Если же запись не производится, то любое число задач может получить доступ к данным для чтения. Как мы увидим далее, указанные правила могут быть детализированы, но сначала мы рассмотрим решение для простого случая.
Очевидным решением является использование для управления доступом задачи-планировщика. На рис. 5.12 проиллюстри-
ровано это решение в предположении, что есть несколько считывающих задач (READER) и только одна записывающая (WRITER). У задачи-планировщика имеются входы REQUEST-READ (ЗАПРОС-ЧТЕНИЯ), REQUEST-WRITE (ЗА- ПРОС-ЗАПИСИ) и FIN (КОНЕЦ). Задачи READER, которые вызывают вход REQUEST-READ в то время, когда выполняется операция записи, задерживаются во входной очереди до тех пор, пока процесс записи не закончится. Задача WRITER, обратившаяся к входу REQUEST-WRITE, задерживается во входной очереди до тех пор, пока все считывающие задачи не завершат чтение. Возврат после вызовов REQUEST-READ или REQUESTWRITE означает в этом случае разрешение на продолжение соответственно операции чтения или записи. Задачи обоих типов по окончании работы вызывают вход FIN. В такой постановке проблема управления доступом сводится к задаче упорядочения, которую вполне можно решить с применением концепции конечного автомата в рамках подхода, использованного в системе DIALOGUE из гл. 4. На рис. 5.13 показан соответствующий конечный автомат и программа планирования ресурсов, написанная на языке Ада. Линейная структура взаимодействий в этом проектном решении привлекает четкостью реализации схемы конечного автомата, непосредственным воплощением ее в текст программы, простотой проверки программы на соответствие диаграмме переходов и удобочитаемостью полученного текста программы.
Однако исходная формулировка задачи, которая привела к этому изящному решению, ошибочна, так как в данном случае несколько активных задач READER могут блокировать задачу WRITER на неопределенное время. Такая форма блокировки является примером системной проблемы, называемой голоданием. Это не тупиковая ситуация, поскольку при снижении активности считывающих задач задача WRITER всегда может продолжить свою работу. Проблема голодания менее опасна, чем появление тупиков, но несмотря на это, возникновение ее нежелательно. Правильная постановка должна предусматривать требование, чтобы записывающей задаче разрешалось продолжать выполнение своих функций сразу после того как все активные в текущий момент задачи READER завершат чтение. Такое уточнение постановки вносит элемент специальной дисциплины обслуживания в исходную задачу, а это в свою очередь приводит к тому, что воплощение конечного автомата, показанного на рис. 5.13, в Ада-программу становится не столь очевидным.
Основная сложность, связанная с реализацией уточненной постановки, заключается в том, чтобы найти способ распознавания (без немедленного восприятия) обращения к входу
REQUEST^ WRITE
(а) Схема конечного автомата.
task body RESOURCE_SCHEDULER is
type STATETYPE is (IDLE, READING, WRITING)(
STATE : STATETYPE : = IDLE;
READERS : integer : = 0;
loop
select
when STATE = IDLE = > accept REQUEST_WRITB
do STATE : = WRITING; end; or when STATE * WRITING = > accept REQUEST_READ do case STATE is
when IDLE = > STATE : = READING; READERS : = READERS + It
when READING = > READERS : = READERS + 1;
end case;
end;
or
when STATE / IDLE = >
accept FIN do case STATE is when READING = > READERS : = READERS if READERS = 0 then
STATE : = IDLE; end if;
when WRITING = > STATE : = IDLE;
end;
end select;
end loop;
end RESOURCE-SCHEDULER;
(5) Программа на языке Ада,
Рис. 5.13. Реализация синхронизации процессов чтения и записи (вариант 1)''»
REQUEST-WRITE в состоянии READING (ЧТЕНИЕ)' и переводить по этому событию конечный автомат в новое состояние. В этом новом состоянии очередные вызовы REQUEST-READ приниматься не должны, и только после приема вызовов FIN от всех активных считывающих задач будет принято обращение к входу REQUEST-WRITE и наступит состояние WRITING (ЗАПИСЬ). Естественно было бы, следуя предыдущим
примерам, принять вызов REQUEST-WRITE в состоянии READING, а затем соответствующим образом изменить состояние. Однако при этом (если и далее строго следовать предыдущим примерам) очередным шагом должно было бы стать окончание рандеву по входу REQUEST-WRITE и вхождение заново в условный оператор приема через ^заблокированный для нового состояния вход. Но тем самым мы ошибочно разрешили бы запись тому модулю, от которого исходил вызов входа REQUEST-WRITE.
Другой вариант решения, в котором используются вложенные рандеву, приведен на рис. 5.14. , Хотя этот способ обеспечивает получение результата, он не дает явного отображения конечного автомата в Ада-программу с линейной структурой взаимодействий. Во-первых, в полученной программе имеется неявное состояние чтения с ожиданием записи, а во-вторых, трудно изобразить для этого решения схему интерфейса, поскольку обращение к входу FIN принимается в двух точках, одна из которых находится внутри вложенной структуры, а другая — вне ее.
Тем не менее явное представление конечного автомата может быть получено довольно легко, если принять во внимание тот факт, что в состоянии READING условия для предстоящей записи не могут измениться до тех пор, пока не поступит очередной вызов FIN. Следовательно, при выполнении соответствующего этому вызову оператора приема можно проверить очередь на входе REQUEST-WRITE и произвести необходимые изменения состояний. Указанным способом можно в конечном итоге предотвратить голодание записывающей задачи, однако в этом случае несколько дополнительных считывающих задач могут «проскользнуть» в очередь до поступления следующего вызова FIN. Мы можем ограничить число таких задач до одной, организуя перекрестную проверку входной очереди REQUEST-WRITE при приеме вызова REQUEST-READ, который последует за обращением к входу REQUEST-WRITE. Для того чтобы еще сильнее воспрепятствовать проникновению даже одной дополнительной задачи READER, можно периодически просматривать входную очередь REQUEST-WRITE в промежутках между вызовами вместо простого ожидания внешнего вызова. Представление этого проектного решения в виде схемы конечного автомата приведено на рис. 5.15, а, а соответствующая Ада-программа, непосредственно реализующая этот конечный автомат, изображена на рис. 5.15,6.
Основополагающая идея решения, приведенного на рис. 5.15, заключается в рассмотрении счетчика входной очереди REQUEST-WRITE в качестве вспомогательной переменной, влияющей на переходы из одного состояния в другое, которые осу-
Вход явнозаблокированв состоянииWRITINGВход явнозаблокированв состоянииWRITING(а) Структурный граф, содержащий одновременновложенный и защищенный операторы приема(нелинейная структура взаимодействий).(а) Структурный граф, содержащий одновременновложенный и защищенный операторы приема(нелинейная структура взаимодействий).Задача RESOURCE .SCHEDULERЗадача RESOURCE .SCHEDULERВход явно заблокирован только в состоянииWRITINGВход явно заблокирован только в состоянииWRITINGВход неявно заблокирован вложенным оператором приема FIN в неявном состоянии READING-WAITINGJO.WRITEВход неявно заблокирован вложенным оператором приема FIN в неявном состоянии READING-WAITINGJO.WRITE
Вход явнозаблокированв состоянии
WRITING
Вход явнозаблокированв состоянии
WRITING
(а) Структурный граф, содержащий одновременновложенный и защищенный операторы приема(нелинейная структура взаимодействий).
(а) Структурный граф, содержащий одновременновложенный и защищенный операторы приема(нелинейная структура взаимодействий).
Задача RESOURCE .SCHEDULER
Задача RESOURCE .SCHEDULER
Вход явно заблокирован только в состоянии
WRITING
Вход явно заблокирован только в состоянии
WRITING
Вход неявно заблокирован вложенным оператором приема FIN в неявном состоянии READING-WAITINGJO.WRITE
Вход неявно заблокирован вложенным оператором приема FIN в неявном состоянии READING-WAITINGJO.WRITE
ществляются в моменты обращений к другим входам или по истечении отведенного лимита времени. Данное решение, однако, перестает быть правильным, если выдвигается требование, чтобы ни один вызов REQUEST-READ не принимался, после того как выполнен оператор приема, соответствующий входу REQUEST-WRITE. При таком подходе допускается принять единственный вызов REQUEST-READ в состоянии READING, но уже после того как принят вызов REQUEST-WRITE и до поступления вызова FIN.
Вложенный операторприема FIN в неявномсостоянии
READING_WAITING_TO_WRITE; благодаря ему рандеву
REQUEST-WRITE не кончаетсядо тех пор, покане будут выполненыоператоры приема FINвсех считывающих задач
(б) Схема конечного автомата с неявным состоянием.
select
when STATE * WRITING = >'
accept REQUEST_WRITE do case STATE is
when IDLE = > STATE : = WRITING;
when READING = > loop
accept FIN;
READERS : = READERS - 1; if READERS = 0 then STATE : = WRITING; exit; end if; end loop-
end case; end; or
When STATE / WRITING = > accept REQUEST_READ do case STATE is when IDLE = > STATE : = READING; READERS : = READERS + 1;' when READING = > READERS : = READERS + 1; end case; end; or when STATE * IDLE = > accept FIN do case STATE is
When READING = > READERS : = READERS - 1;
if READERS = 0 then STATE ; = IDLE; end if;
when WRITING = > STATE : = IDLE; end case; end; end select;
(в) Фрагмент программы, отображающий нелинейную структуру взаимодействий. .
Рис. 5.14. Реализация синхронизации процессов чтения и записи (вариант 2), нелинейная структура взаимодействий.
Линейная структура взаимодействий для окончательного варианта схемы синхронизации операций чтения-записи может быть реализована путем организации для задачи WRITER двух входов вместо одного: POST-WRITE (АБОНИРОВАНИЕ, ЗАПИСИ) и WAIT-WRITE (ОЖИДАНИЕ-3АПИСИ). По первому из них будет выставляться требование на запись, а по второму — реализовываться ожидание удовлетворения выставленного требования в том случае, если оно не может быть выполнено немедленно по причине активного состояния задачи READING. При наличии только одной записывающей задачи нужно иметь защитную блокировку лишь на входе, по которому осуществляется ожидание. В противном случае должен защищаться и вход POST-WRITE во избежание процесса со-
стязания сразу нескольких записывающих задач за доступ к входам POST_WRITE и WAIT.WRITE. Пользовательский интерфейс можно оставить без изменения, поместив задачу распределения ресурсов внутрь активного пакета. Это проектное решение проиллюстрировано на рис. 5.16. Логика конечного автомата для нового решения в основном совпадает с логикой конечного автомата на рис. 5.15, за исключением того, что
ОжиданиеОжидание окончанияокончанияработы текущих 'ОжиданиеОжидание окончанияокончанияработы текущих 'Окончание лимита времени при незакон ченной обработке текущего запроса на записьОкончание лимита времени при незакон ченной обработке текущего запроса на записьeequest_readeequest_readREQUEST_READREQUEST_READREADINGREADINGREQUEST„WRITEREQUEST„WRITEWRITINGWRITINGREQUEST„WRITEREQUEST„WRITEПоследний " вызов FINПоследний " вызов FINWRITE,WRITE,READYREADYFIN приFIN принезакон-незакон-ченмоиченмоиобработкеобработкевызовавызоваWRITEWRITEПоследнийПоследнийвызов FINвызов FINREQUEST-READREQUEST-READпри незаконченнойпри незаконченнойобработке вызоваобработке вызоваWRITE—REQUESTWRITE—REQUESTREAD,READ,FINISHFINISHREQUESTREQUEST(6) Схема конечного автомата,(6) Схема конечного автомата,
ОжиданиеОжидание окончания
окончанияработы текущих '
ОжиданиеОжидание окончания
окончанияработы текущих '
Окончание лимита времени при незакон ченной обработке текущего запроса на запись
Окончание лимита времени при незакон ченной обработке текущего запроса на запись
eequest_read
eequest_read
REQUEST_READ
REQUEST_READ
READING
READING
REQUEST„WRITE
REQUEST„WRITE
WRITING
WRITING
REQUEST„WRITE
REQUEST„WRITE
Последний " вызов FIN
Последний " вызов FIN
WRITE,
WRITE,
READY
READY
FIN при
FIN при
незакон-
незакон-
ченмои
ченмои
обработке
обработке
вызова
вызова
WRITE
WRITE
Последний
Последний
вызов FIN
вызов FIN
REQUEST-READ
REQUEST-READ
при незаконченной
при незаконченной
обработке вызова
обработке вызова
WRITE—REQUEST
WRITE—REQUEST
READ,
READ,
FINISH
FINISH
REQUEST
REQUEST
(6) Схема конечного автомата,
(6) Схема конечного автомата,
task body RESOURCE_SCHEDULER is
type STATETYPE is (IDLE, READING, WRITING, READ_FINISH);
STATE : STATETYPE :.= IDLE;
READER : integer: = 0;
loop
select
when STATE = IDLE or STATE = WRITE_READY = >accept REQUEST_WRITE'
do STATE : = WRITING; end;
or
when STATE = IDLE or STATE = READING = >
accept REQUEST_READ do case STATE is
when IDLE = > STATE : = READING;
READERS : = READERS* 1;
when READING = >
READERS : = READERS* 1;
if REQUEST_WRITE' COUNT>0>
then STATE : - READ_FINISH;
end if;
end case;
end;
. or
when STATE * IDLE or STATE * WRITE—READY = > accept FIN
do case STATE is
when WRITING = > STATE : = IDLE;
when READ_FINISH = >
READERS : = READERS-1;
if READERS = 0
then STATE : = WRITE_READY; end If;
When READING = >
READERS : = READERS-1;
if READERS = 0
then STATE : = IDLE;
else if REQUEST_WRITE' COUNT>0
then STATE ; = READ_FINISH;
end if;
end case; end;•
or
delay TIMEOUT_PERIOD;
if REQUEST—WRITE'COLJNT>0
then STATE : = READ_FINISH;
end if;
end select;
end loop;
end RESOURCE—SCHEDULER;
(в) Ада-программа для случая линейной структуры взаимодействий.
Рис, 5.15, Реализация синхронизации процессов чтения и записи (вариант 3)«
(а) Структурный граф.
1,Вход заблокирован, пока не закончена запись. 2 Вход заблокирован, пока* не закончена запись. З.Вход заблокирован, пока не закончено чтение. -
l.Bce переходы осуществляются по вызову входа. 2.В качестве
•- средств защиты используются значения переменных состояния.
Рис, 5.16, Реализация синхронизации процессов чтения и записи (вариант 4) линейная структура взаимодействий в форме пакета.
переход из состояния READING в состояние READ-FINISH (ЧТЕНИЕ-ОКОНЧЕНО) осуществляется при приеме обращения к входу POST-WRITE, а переход из состояния WRITEREADY (ЗАПИСЬ-ПОДГОТОВЛЕНА) в состояние WRITING (ЗАПИСЬ)—при приеме обращения к входу WAIT-WRITE. Для обеспечения приоритета записывающих задач перед считывающими в состоянии IDLE (ПРОСТОЙ) можно использовать механизм реализации приоритетов, представленный на рис. 3.16. В качестве упражнения читателю предлагается написать программу тела задачи синхронизации операций чтения — записи.
Пример задачного пула AGENT-POOL
Рассматриваемый ниже пример AGENT-POOL (АГЕНТСТВО) характеризуется большей общностью по сравнению с примером системы BANK. Каждая из задач, реализующих функции служащего агентства, может быть абонирована и освобождена клиентом в результате явного запроса. В интервале между абонированием и освобождением служащий агентства (агент) доступен для многократного общения с клиентом, к которому он «прикреплен». Предполагается, что в процессе этого общения агент должен располагать возможностью автономных действий, иначе формирование задачи-агента оказывается неоправданным. Некоторые интересные и важные вопросы взаимодействия задач возникают при рассмотрении взаимодействий между диспетчером агентства, клиентами и агентами. Соответствующие примеры приведены на рис. 5.17.
Основная идея решения для данного примера иллюстрируется на рис. 5.17. а. Сходство с банковским примером здесь очевидно, оно проявляется в использовании переменной целого типа (#) для идентификации агента, при вызове диспетчера по входу DISPATCHER-FREE (ДИСПЕТЧЕР-СВОБОДЕН) свободным агентом, взаимодействии клиента с входами RESERVE (РЕЗЕРВИРОВАНИЕ) (аналогичными входу WAIT, в банковской системе) и ASK (ЗАПРОС). Новой чертой является наличие в явном виде входа CANCEL (ОТМЕНА) в задаче- агенте. После приема обращения к входу CANCEL задача- агент вызывает вход FREE для передачи диспетчеру своего идентификационного номера.
В зависимости от выбранного конкретного решения агенты могут ожидать или не ожидать реакции диспетчера. Рассмотрим эти варианты по порядку.
Линейная структура взаимодействий с ожиданием показана на рис. 5.17,6. Здесь агент вызывает сначала незаблокирован- ный вход FREE, а затем обращается к защищенному входу
диспетчера через WAIT. Идея решения состоит в том, что через вход FREE диспетчер получает номера свободных агентов, которые затем могут быть сообщены клиентам через вход RESERVE, после чего абонированные задачи могут быть освобождены от ожидания путем выполнения оператора приема, принадлежащего входу WAIT. Такая схема, однако, не гарантирует того, что все обращения к входам FREE и WAIT будут выполняться именно в таком порядке всеми задачами- агентами. Состязание между ними за право доступа к этим входам может привести к нарушению должного порядка вызовов, а в конечном счете и к тому, что клиенту будет сообщен не тот номер агента.
Проблема состязаний может быть разрешена путем преобразования входов WAIT на рис. 5.17,6 в семейство входов с тем же именем, помеченное номером агента. Линейность структуры при этом сохраняется.
(а) Базовое решение (процедура инициализации.опущена)
(6) Линейная структура взаимодействий с ожиданием^
(в) Нелинейная структура взаимодействий с ожиданием.
(г) Линейная структура взаимодействий без ожидания при. наличии состязания между клиентом и диспетчером.
(д) Линейная структура взаимодействий без ожидания, исключающая возникновения состязания.
Рис. 5.17. Структура взаимодействий в системе AGENT—POOL. Предполагается, что номера агентов в момент инициализации не меняются.
Проблема состязаний может быть разрешена также с использованием нелинейного вложенного оператора приема, как показано на рис. 5.17, а. Такое решение позволяет избежать ситуации состязания между агентами и обеспечивает получение правильных номеров агентов клиентами. Однако этот подход оказывается потенциально сложным при наличии большего числа входов к диспетчеру, что будет продемонстрировано в примере из гл. 7.
Линейная структура взаимодействий без ожидания представлена на рис. 5.17, г. Новый вход RESERVE, принадлежащий задаче-агенту, требуется для уведомления агента о том, что его абонировали; в ответ на это задача-агент, возвращая соответствующее значение параметра состояния STATUS, может сообщить абоненту о своей готовности или неготовности начать работу. Решение, представленное на рис. 5.17, г, предусматривает обращение диспетчера к входу RESERVE задачи- агента, здесь создается возможность состязания между клиентом и диспетчером за первенство в осуществлении вызова агента. Но если вызов, исходящий от диспетчера, не будет принят первым, то правильно выполненный запрос клиента через вход ASR будет отклонен. Борьбу с указанным явлением можно было бы возложить на интерфейсную процедуру пакета, организуя по истечении некоторого времени повторное обращение клиента. Однако это не лучшее решение.
Лучше сделать так, как показано на рис. 5.17,5, где в составе пакета имеется процедура RESERVE, которая реализует обращение к входу RESERVE задачи-агента с целью уведомления об абонировании ее клиентом, а затем возвращает управление клиенту.
Заключение
Применение линейных структур взаимодействий желательно по причинам, сформулированным в начале подразд. 5.3.1. Они могут быть организованы на основе соответствующего структурирования условий ожидания, как в примерах подразд. 5.3.1 и 5.3.3. При использовании линейных структур взаимодействий необходимо принимать меры по предотвращению возможных ситуаций состязания между задачами за общие ресурсы, как было показано в подразд. 5.3.3. Если же все-таки желательно применение нелинейных структур взаимодействий, то графические средства их отображения можно найти в подразд. 5.3.1 и 5.3.3.
Механизм уведомления о событиях
Важным аспектом взаимодействия модулей является уведомление о происходящих событиях, которое может выполняться как синхронное или асинхронное.
Синхронное уведомление о событии исходит от вызываемого модуля при обработке вызова (процедуры или входа) и адресуется вызывающему модулю. Оно может быть осуществлено путем пересылки выходных параметров вызова или посред-
ством распространения исключительных ситуаций на вызывающий модуль на период обработки вызова.
Асинхронное уведомление о событии может формироваться в любое время. Оно может служить ответом на предыдущие вызовы, но существует отдельно от них.
Основное внимание в этом разделе будет уделено синхронному уведомлению. Асинхронное уведомление может быть реализовано соответствующим механизмом связи между задачами. Однако, прежде чем перейти к рассмотрению проблемы синхронного уведомления, уместно задаться вопросом: возможен ли какой-либо иной способ оповещения задач о происходящих асинхронно событиях, чем обычная связь между задачами с использованием механизма рандеву? Ответ на этот вопрос будет отрицательным, за исключением особого случая завершения выполнения задачи. Исключительные ситуации, возникающие при выполнении оператора приема, могут быть распространены на вызывающую задачу как исключения, соответствующие точке обращения к ее входу. Однако в связи с тем, что подобное распространение исключений происходит во время рандеву, это будут скорее синхронные, нежели асинхронные уведомления.
Теперь обратим внимание исключительно на синхронное уведомление о событиях. Передача его в вызывающий модуль путем пересылки выходного параметра вызова процедуры или входа является вполне приемлемым способом оповещения о событии, причем фактически только этот способ и использовался во всех предыдущих примерах. Зачем же тогда нам нужно привлекать еще и исключительные ситуации?
Прежде чем ответить на этот вопрос, рассмотрим природу исключительных ситуаций в языке Ада. В самом простом случае механизм исключительных ситуаций позволяет передать сообщение об ошибке, обнаруженной в процессе обработки вызова, в блок обработки исключений в вызывающем модуле путем аварийного возврата из процедуры вызова.
Таким образом, рассматриваемый механизм просто дает возможность отделить ту часть программы, в которой происходит обработка ошибок, от программы, соответствующей режиму отсутствия ошибок. Это удобно для программиста, но можно показать, что подобное разделение вредно в практике разработки программного обеспечения, так как нормальная последовательность выполнения операций и обработка ошибок при проектировании не должны разделяться.
Одна очень важная особенность механизма исключительных ситуаций в языке Ада заключается в том, что не все исключения должны описываться программистом, некоторые из них определены в самом языке и при обнаружении ошибки порож-
даются с помощью фрагментов программы, которые автоматически генерируются компилятором. Механизм обработки исключительных ситуаций не зависит от того, какого типа исключение имеет место: определенное программистом или порождаемое компилятором. Таким образом, Ада-программа способна обрабатывать ошибки, которые в программах на других языках привели бы к прекращению выполнения программы. Все вышесказанное является убедительным аргументом в пользу применения механизма исключительных ситуаций. К сожалению,
Обработчик X не виден для В
(а) Концептуальное представление.
(6) Пример
Рис. 5.18. Система условных обозначений для построения структурного графа распространения исключительных ситуаций.
имеются аргументы и против, поскольку правила использования исключительных ситуаций в языке Ада сложны и противоречивы.
И все же, вероятно, могут встретиться обстоятельства, при которых разработчик захочет воспользоваться механизмом исключений; поэтому необходимо иметь на этот случай систему обозначений для построения структурных графов. В гл. 3 подходящей графической нотации не было.
Исходя из того, что все исключения объявляются в спецификации вызываемого модуля, а обрабатываются в теле вызывающего, распространение действия исключительных ситуаций является в графическом отображении чем-то вроде вызова про-
цедуры в обратном направлении (рис. 5.18, а). Здесь видимая извне исключительная ситуация X в модуле В, изображенном справа, вызывает запуск невидимого внутреннего обработчика исключений в модуле А, изображенном слева. Исключение X объявлено в модуле В так, что оно является видимым для модуля А, и поэтому известно заранее, что в модуле А необходим блок обработки исключений. Когда возникает исключительная ситуация X в модуле В (во время вызова, направленного от А к В), сообщение об этом передается обработчику исключений в модуле А, невидимому для модуля В. Рис. 5.18,6 иллюстрирует вышеизложенное для случая распространения исключительной ситуации из пакета В в процедуру А. Здесь процедура А вызывает процедуру b из пакета В, и при выполнении ее возникает исключительная сутация X, действие которой распространяется далее на оператор вызова, принадлежащий процедуре А. Обработчик исключения X должен размещаться в А, но он невидим для пакета В. Чтобы исключение X стало видимым для объекта, вызывающего пакет В, оно должно быть объявлено в спецификации пакета В, как и процедура Ь.
Хотя уведомления об исключительных ситуациях могут передаваться от В кА, когда либо только А, либо А и В являются задачами, не существует никакого механизма для
package STACK is
procedure PUSH (E : in ELEM);
procedure POP (E : out ELEM);
OVERFLOW, UNDERFLOW : exception;
end STACK;
package body STACK is
SPACE I array (1 .. SIZE) of ELEM;
INDEX : INTEGER range 0 .. SIZE : = 0;
procedure PUSH(E : in ELEM) is begin
if INDEX = SIZE then
raise OVERFLOW;
end if;
INDEX : = INDEX + 1;
SPACE(INDEX) : = E;
end PUSH;
procedure POP(E : out ELEM) is
begin
if INDEX = 0 then
raise UNDERFLOW;
end if;
E : = SPACE(INDEX);
INDEX : = INDEX - 1;
end POP;
end STACK;
Ада-программа (написанная в соответствиис руководством по языку Ада).
Рис. 5.19. Стековый пакет с внешней обработкой исключений.
Условные обозначения:
OVERFLOW ПЕРЕПОЛНЕНИЕ
UNDERFLOW НЕДОГРУЗКА
объявления исключений в спецификациях задач. Эта трудность наряду с другими приводит к усложнению организации обработки исключений в рамках взаимодействий задач.
При рассмотрении исключительных ситуаций на уровне проектных решений в аспекте построения структурных графов мы видим, что наличие исключений далеко не упрощает ситуацию, а, наоборот, усложняет ее, выделяя и подчеркивая фоновую теневую структуру системы, связанную с обработкой исключений и отличную от структуры, отражающей номинальный режим функционирования системы. Зачем же тогда нужно вводить это дополнительное усложнение?
По твердому убеждению автора, исключительные ситуации следует использовать не глобально как механизм синхронного уведомления о событиях, действующий между основными модулями системы, а локально внутри модулей для специальных целей, например при необходимости обработки стандартных ошибок, обнаруживаемых с помощью автоматически генерируемых фрагментов программ.
Несмотря на отмеченную позицию автора, некоторые разработчики, возможно, все равно захотят использовать механизм исключительных ситуаций в более общих случаях. Именно поэтому на рис. 5.19 проиллюстрировано более подробно использование исключительных ситуаций применительно к стековому пакету из гл. 2.
Контроль и обнаружение аномального поведения модулей
Тестирование
При объединении модулей в систему и последующем ее тестировании наверняка будут обнаруживаться ошибки. Ошибки могут также возникать (по предположению не очень часто) и при функционировании системы, если в процессе тестирования их обнаружить не удалось. Поэтому проектировщику необходимо иметь средства для определения характера взаимодействия модулей в аномальных ситуациях, с тем чтобы уметь обнаруживать, регистрировать и локализовать возникающие ошибки.
Мы будем рассматривать здесь не просто отладку, средства которой в той или иной степени будут поддерживаться программным обеспечением любой конкретной вычислительной системы, оснащенной транслятором с языка Ада. Объектом нашего внимания будет проектирование испытательных инструментальных средств, предназначенных для использования в действующей системе.
Например, может оказаться желательным создание специальных межмодульных интерфейсов, обеспечивающих обход обычных правил взаимодействия модулей (например, для получения доступа к локальным переменным пакета, которые при стандартном описании в спецификации пакета невидимы). Автор успешно пользовался этим методом в различных проектах, где применялись мониторы, которые представляли собой специальные пакеты, предназначенные для защиты взаимодействующих задач в целом ряде систем, функционирующих в среде языка Ада. В этих проектах испытательным программам
Рис. 5.20. Структурный граф, соответствующий аварийному прекращению выполнения задачи.
разрешалось обходить стандартные пути доступа к монитору с целью получения возможности считывания значений его локальных переменных.
К сожалению, в языке Ада нет явного механизма для определения в пакетах или задачах сразу нескольких интерфейсов различного назначения. У каждого пакета или задачи имеется единственная спецификация, и доступ к ним возможен только тем способом, который указан в этой спецификации.' Обойти указанное ограничение можно только путем включения конкретных нужных интерфейсов в спецификацию и детального описания их с помощью комментариев в рабочем варианте системы.
Разработчикам систем программного обеспечения было бы полезно также иметь возможность самим определять целесообразность включения конкретных тестовых фрагментов в программы, т. е. желателен некоторый механизм условной компиляции. К сожалению, в языке Ада такого механизма нет. Опять необходимо создание специальных фрагментов, которые могут быть включены в программу и снабжены соответствующими комментариями в рабочем варианте системы.
При проектировании важно, кроме того, определить некоторые способы обнаружения сбоев и прекращения выполнения задач или активных пакетов, в которых произошел сбой, без прерывания выполнения основной программы, с тем чтобы можно было по промежуточным результатам установить причину сбоя. Но если проблема обнаружения неисправных модулей может быть решена с помощью внутренних инструменталь-
ных средств тестирования программы, то с прекращением выполнения задач и активных пакетов дело обстоит сложнее.
В частности, неясно, как можно прекратить выполнение «подозрительных» задач, если ошибка произошла в момент, когда они не взаимодействуют с другими модулями в рамках рандеву. Правда, один способ очевиден—некоторая задача аварийно прекращает выполнение другой (рис. 5.20). Такое действие является безотлагательным и может произойти в момент выполнения любой операции, вследствие чего данные могут остаться в неопределенном состоянии. Но, поскольку по предположению задача выполняется некорректно, ее данные и так считаются неприемлемыми.
Конечно, можно представить себе применение этого механизма в процессе нормального функционирования системы, однако в основном его следует использовать в рамках системного тестирования. Например, можно прерывать выполнение «подозрительных» задач, в которых предполагаются ошибки, для проведения процедур диагностики.
В некоторых случаях задачу, в которой произошла ошибка, можно выявить на основе анализа внешних событий. Например, если в процессе тестирования требуется, чтобы задачи че-
(а) Для пакетов.
Тестовый доайвер
(б) Для задач.
Рис. 5.21. Возможная структура исполнительных средств в среде языка Ада. рез определенные промежутки времени наращивали показания своих специальных счетчиков в области памяти, называемой тестовым журналом и доступной средствам отладки, то задачу, в которой произошел сбой, можно определить, используя тот факт, что значение ее счетчика не увеличивается.
С учетом рассмотренных выше особенностей Ада-программ на рис. 5.21 показана возможная структура отладочных средств для пакетов и задач, написанных на языке Ада. Специализированный испытательный пакет или испытательная задача должны содержать специальный тестовый регистратор и, возможно, специальный запускающий интерфейс, с помощью которых пакеты или задачи должны записывать значения своих локальных переменных во внешний для них тестовый журнал. Тестовый журнал может анализироваться в нужных точках испытательными средствами в моменты времени, определяемые, например, исключительными ситуациями, возникающими
в рамках пакета. Этот пакет должен содержать внутри программы, соответствующей нормальному режиму функционирования, вложенные операторы для активизации пакета тестового регистратора, который должен фиксировать все существенные события, такие, как прохождение определенной точки в программе, нарушение конкретного условия и т. п.
Как видно из рис. 5.21,6, единственное изменение, которое требуется внести в описанный выше механизм для пакетов применительно к задачам, заключается в том, что в тестовом драйвере необходимо предусмотреть одну или несколько сторожевых задач, которые обеспечивали бы аварийное прекращение выполнения подозрительных задач.
Самозащита с помощью межзадачных протоколов
Поскольку задачи являются автономными объектами, невозможно всегда с полной уверенностью гарантировать, что вызываемая задача получила адресованное ей сообщение. Рассмотрим рис. 5.22, на котором изображен межзадачный диалог.
Рис. 5.22. Простой способ передачи сообщений между задачами.
Такой диалог может возникнуть, например, между задачей-клиентом и пакетом MAIL-ROOM, функционирование которого обсуждалось ранее. Предположим, что отправитель сообщения не получил на него ответа. Это может произойти по следующим причинам:
сообщение не дошло до задачи-адресата;
.• задача-адресат больше не существует (возможно, потому, что она выполнялась процессором, который вышел из строя);
? несмотря на то что и отправитель, и адресат хотят осуществить рандеву, возникшее затруднение внутрисистемного характера делает это невозможным (например, задачи выполняются на разных процессорах, связь между
, которыми нарушена);
существует ошибка в задаче, которой адресовано сообщение.
Все эти причины вполне вероятны, кроме первой, которая нереальна вследствие физической сущности самого механизма рандеву; возврат из процедуры вызова входа SEND свидетельствует о получении сообщения адресатом. В этом смысле механизм рандеву является более надежным, чем просто передача сообщения, например, через общую память с помощью почтового ящика электронной почты.
Разумной реакцией со стороны отправителя на то, что он не получил ответа, может быть попытка заново передать сообщение. Однако при этом адресат может получить сразу несколько копий одного и того же сообщения. Поэтому необходимо какое-то соглашение между отправителем и получателем, в соответствии с которым можно было бы идентифицировать различные экземпляры сообщений. Иначе говоря, требуется определенный протокол взаимодействия отправителя и получателя.
Протокол представляет собой формализованный диалог между автономными элементами системы, предназначенный для обеспечения надежной связи между ними, т. е. для защиты от влияния возможных сбоев в каждом из них, а также в линии связи, но не в самом протоколе. Обычно протоколы рассматриваются применительно к организации связи между отдельными элементами вычислительной сети, однако их можно использовать и для организации функционирования задач, написанных на языке Ада.
Хотя создается впечатление, что механизм рандеву исключает необходимость применения протокола управления передачей сообщений, которые могут не дойти до получателя, это в какой-то части является чистой иллюзией. Чтобы убедиться в этом, достаточно вспомнить гл. 3 и 4, где отмечалось, что часто оказывается необходимым использовать задачу-посредник между отправителем и получателем, которая играет роль курьера, доставляющего сообщения, или обеспечивает их хранение. Если даже все рандеву, используемые при взаимодействии между двумя исходными задачами и задачей-посредником, являются абсолютно надежными, сообщения все же могут не дойти до адресата. Должны ли мы в связи с этим беспокоится о протоколах на уровне Ада-программ? Ответ будет зависеть от конкретных возможностей и аппаратного окружения целевой вычислительной системы.
Если, например, в системе имеется всего один процессор, то следует предположить, что сообщение не дошло до адресата в результате фатальной ошибки, происшедшей по вине аппаратуры или программного обеспечения. В этом случае должны подвергаться сомнению результаты работы всех программ, выполняемых данным процессором, и, следовательно, нет необходимости заботиться о межзадачных протоколах.
Если же вычислительная система состоит из нескольких процессоров с общей памятью или общими каналами связи, то существует вероятность отказа как самих процессоров, так и совместно используемых ими ресурсов. Если к тому же требуется полная независимость проектируемых Ада-программ от аппаратных средств целевой вычислительной системы (т. е. необходимо, чтобы любая задача могла выполняться на любом из процессоров), то все межзадачные взаимодействия оказываются потенциально ненадежными. В этих условиях создание механизмов восстановления на программном уровне для всех вероятных нарушений нормальной работы системы было бы трудным, неоправданно дорогостоящим, а зачастую и просто невозможным; такие механизмы должна была бы обеспечивать целевая система.
Однако задачи часто будут естественным образом распадаться на отдельные множества, причем связи между множествами будут тесными, а внутри множеств — свободными в определенном смысле. Если потребовать, чтобы такие множества были закреплены как неделимые блоки за индивидуальными процессорами, то проблема восстановления станет менее сложной. Все задачи в таком блоке имеют надежную связь друг с другом до тех пор, пока блок функционирует нормально. Если по какой-либо причине произошла ошибка, все задачи конкретного блока становятся потенциально подозрительными, а дефектный блок может быть изолирован от всех других.
Во всех таких блоках необходимо, следовательно, принимать во внимание лишь возможность сбоя в других блоках и в линиях связи между ними. Каждому блоку ставится в соответствие коммуникационный пакет, который обеспечивает надежную связь с остальными блоками. Мы будем называть такие блоки узлами надежности. Концепция узлов надежности может поддерживаться на программном уровне или на уровне аппаратных средств целевой системы.
Сущность такого подхода применительно к программному уровню проиллюстрирована на рис. 5.23 на примере взаимодействия отправителя и адресата (рис. 5.22) в предположении, что отправитель и адресат располагаются в разных узлах надежности. Активный коммуникационный пакет в каждом узле надежности служит для организации пересылки обращений к входам задач, принадлежащих другим узлам надежности. Отправитель должен использовать этот пакет для того, чтобы вызывать вход SEND задачи адресата. Коммуникационный пакет адресата выполнит затем требуемый вызов (возможно, путем порождения задачи-партнера) и передаст уведомление о завершении рандеву; до тех пор пока это уведомление не будет получено, отправитель будет находиться в заблокированном состоянии. В об-
Рис. 5.23. Пересылка обращения к входу между различными узлами надежности.
Обозначение:
FORWARD ПРОДОЛЖЕНИЕ
ратном направлении аналогичным способом будет передан вызов REPLY (ОТВЕТ). Возможны также и другие способы организации связи между узлами надежности, но в любом случае узлы надежности делаются видимыми для взаимодействующих задач.
При реализации концепции узлов надежности на уровне аппаратных средств целевой системы должна предусматриваться прозрачность узлов надежности (для коммуникационных задач). Тогда обращения к входам на программном уровне смогут осуществляться между задачами в различных узлах надежности непосредственно.
Однако, учитывая большой объем работы, которую еще предстоит провести для того, чтобы язык Ада и средства его
поддержки появились на однопроцессорных ЭВМ и многопроцессорных вычислительных системах с общей памятью, приходится признать, что нужная нам распределенная система вряд ли появится в ближайшем будущем.
И все же концепция узлов надежности будет полезна еще долгое время независимо от того, будут ли созданы распределенные средства ее поддержки в среде языка Ада. Единственный недостаток этого подхода заключается в том, что программу на языке Ада для целевой распределенной вычислительной системы нельзя писать без учета конкретного распределения программных средств по узлам этой системы.
Компоновка систем
Язык Ада характеризуется в этой книге (да и в других источниках) как язык структурной компоновки систем. Мы попытались проиллюстрировать структурное проектирование систем средствами языка Ада. Однако под структурной компоновкой систем обычно понимается не только их проектирование, но и разработка, установка и реконфигурация. В связи с этим мы рассмотрим ниже ряд проблем, с которыми приходится сталкиваться разработчикам систем, и покажем, в какой степени язык Ада создает условия для их решения.
Довольно естественным требованием к проектированию является обеспечение возможности загрузки и выполнения под управлением Ада-программы программных модулей, написанных на языке Ада и заранее не известных загружающей программе. Однако средства языка Ада не обеспечивают такой возможности, и именно поэтому язык Ада нельзя использовать для проектирования и программирования традиционных операционных систем, которые должны работать с не известными априори программами пользователя.
Концептуальное единство, достигаемое при проектировании систем с использованием одинаковых интерфейсов пакетов и задач, является тем важным фактором, который не раз уже рассматривался в процессе нашего обсуждения. В результате мы выяснили, что пакеты и задачи являются модулями одного и того же логического уровня. Может показаться теперь, что пакеты и -задачи следует трактовать одинаково и на уровне компоновки систем. Однако на самом деле это не так. В языке Ада пакеты могут создаваться только при написании программ; в крайнем случае экземпляры родовых пакетов могут быть получены на этапе компиляции.
Поскольку пакеты могут быть компилируемыми объектами, они представляют собой те модули, из которых компонуется готовая система. Что касается задач, то их нельзя рассматри-
вать как компилируемые объекты, за исключением тех случаев, когда тела задач представлены заглушками. Для задач в языке Ада определяются типы, а экземпляры конкретных типов могут создаваться динамически в ходе выполнения программы.
Зачем же требуется вводить эти различия между пакетами и задачами, когда в рамках процесса проектирования их желательно рассматривать как сходные логические объекты? Разработчики языка Ада трактуют пакеты как достаточно крупные статические элементы системы, немногочисленные в сравнении с задачами. В наших примерах это представление оправдывается в тех проектных решениях, где активные пакеты включают несколько задач. Однако мы использовали и такие экземпляры задач, которые содержали пакеты. Подобные задачи при разработке систем должны помещаться внутрь компилируемых объектов, например процедур или пакетов.
Принимая во внимание логическое подобие пакетов и задач на проектном уровне, а также высказанные в гл. 3 соображения о возможности превращения пакетов в задачи и наоборот, в зависимости от требований конкретного приложения можно сделать вывод о желательности такого свойства языка проектирования как наличие возможности откладывать определение данного модуля как пакета или задачи вплоть до момента загрузки. Это позволило бы строить одну и ту же систему как последовательную или параллельную в зависимости от конкретных обстоятельств. Однако язык Ада не предоставляет разработчику таких возможностей.
Глава 6
Модульность, надежность и структурирование: практический пример •
Введение
В этой главе вопросы модульности, надежности и структурных принципов организации систем рассматриваются на конкретном примере коммуникационной подсистемы, используемой в системе DIALOGUE (гл. 4).
Вообще коммуникационные системы информационного обмена хорошо иллюстрируют принципы модульности и надежности, поскольку в тех случаях, когда отправители и адресаты сообщений могут произвольно чередовать передаваемые и принимаемые пакеты, а также менять порядок обслуживания запросов, модульность начинает играть решающую роль в организации взаимодействия вычислительных систем различных типов. Проблема надежности в данном случае весьма существенна ввиду возможности отказа или неправильного выполнения операции как в линиях связи, так и в узлах коммуникационной сети.
Пример, рассматриваемый в этой главе, сознательно упрощен для того, чтобы только проиллюстрировать обсуждаемые вопросы, не затеняя изложение деталями построения сложных протоколов передачи данных. Основной принцип, которого мы придерживаемся и который хотим продемонстрировать в этой главе, заключается в том, что структура хорошо спроектированной системы, реализующей некоторый протокол обмена, не так уж сильно зависит от сложности самого протокола. Другими словами, мы хотим скрыть тонкости протоколов в модулях, интерфейсы которых мало влияют на сложность всей системы. Исходя из этого, мы попытаемся далее спроектировать систему без детального знания протокола обмена. Таким образом, настоящая глава послужит также введением в более сложную область— создание многоуровневых коммуникационных протоколов, что в свою очередь открывает путь к дальнейшему обсуждению этого вопроса в гл. 7.
Материал в данной главе излагается в следующем порядке: в разд. 6.2 приводятся требования к подсистеме СОММ, в разд. 6.3 и 6.4 рассматриваются вопросы модульности и надежности, в разд. 6.5 описывается ее структура, в разд. 6.6 приводятся заключительные замечания, а разд. 6.7 содержит выводы.
Требования к подсистеме СОММ
Как уже упоминалось в гл. 4, система DIALOGUE имеет доступ к системе обмена сообщениями (рис. 4.32), которая в свою очередь является активным пакетом, содержащим две интерфейсные процедуры WAIT-MSG и SEND-MSG, причем процедура WAIT-MSG задерживает выполнение вызывающей ее задачи до момента поступления текста сообщения с терминала удаленной системы, a SEND-MSG обеспечивает передачу сообщения некоторому абоненту. В гл. 4 неявно предполагалось, что, во-первых, имеющийся объем памяти всегда достаточен для хранения входящих и исходящих сообщений; во-вторых, между двумя системами, операторы которых обмениваются сообщениями, существует линия передачи данных, причем считается, что она или абсолютно надежна, или любые возникающие в ней ошибки не проявляются на уровне задач, вызывающих процедуры WAIT-MSG и SEND-MSG.
В этой главе ставится цель — проиллюстрировать принципы модульности и надежности, спроектировав подсистему СОММ, которая реализует интерфейс между системой обмена сообщениями и вызывающими задачами. -
Мы будем предполагать, что программы нижнего уровня подсистемы СОММ обеспечивают взаимодействие с некоторым устройством, управляемым прерываниями, которое осуществляет передачу или прием информации посимвольно. На более низких уровнях обмен происходит последовательно по битам. В данной главе при проектировании системы эти нижние бит- ориентированные уровни рассматриваться не будут. Разумеется, нетрудно представить себе и более сложные устройства, как, например, существующие уже кристаллы, которые обеспечивают в режиме прерываний передачу и прием данных пакетами и осуществляют при этом проверку правильности следования пакетов. Фактически проектную деятельность, описываемую в данной главе, можно представить себе как первый этап проектирования такого кристалла в соответствии со стратегией разработки программно-управляемых систем, изложенной в гл. 1. Однако, руководствуясь целями данной главы, мы будем рассматривать подсистему СОММ как программу, управляющую аппаратным устройством, которое ориентировано на обработку символов.
Предполагается, что аппаратура, обеспечивающая обмен сообщениями между двумя системами, готова к работе всякий раз, когда системы начинают взаимодействовать, т. е. что между ними есть выделенная линия связи. Однако мы не считаем, что эта линия абсолютно надежна — передаваемые данные могут быть искажены шумом или даже полностью потеряны (на-
пример, при временном обрыве линии). При этом в любой ситуации подсистема СОММ должна уметь обнаруживать случаи искажения или потери данных. Мы допускаем также, что системы, соединенные этой линией, могут отключаться или прекращать работу независимо друг от друга; следствием этого является требование к любой из них опрашивать готовность другой перед каждой попыткой передачи данных. На уровне программного обеспечения это требование реализуется двумя протоколами обмена — для включения и выключения линии. В целях упрощения мы возьмем в наш.проект только первый из них.
Естественно также принимать во внимание возможность возникновения отказа в удаленной системе. Опять для простоты будем рассматривать каждый такой случай как отказ линии связи. Таким образом, в наших предположениях могут наблюдаться две ситуации; либо каждая система корректно взаимодействует с остальными, либо совершенно недоступна. Частичный отказ, выражающийся в длительном неверном функционировании коммуникационного протокола, может приводить к фатальным ошибкам на уровне протокола информационного обмена, который рассматривается в данной главе.
' Во избежание ненужных усложнений мы не будем касаться других типов отказов, кроме уже упомянутых кратковременных отказов линии связи, последствия которых устраняются повторной передачей соответствующих частей сообщений. Более длительные отказы могут потребовать более сложных алгоритмов восстановления. Мы предполагаем, что объем памяти, отведенной под буферы обмена, ограничен; поэтому как следствие возникает задача регулирования потока входящих и исходящих сообщений, причем регулирование потока означает здесь временное прекращение поступления данных в систему. В системе DIALOGUE предусмотрено, что оба оператора могут одновременно посылать сообщения друг другу. Это означает, что подсистема СОММ должна обеспечивать передачу и прием сообщений одновременно (т. е. работать в дуплексном режиме). Даже в том случае, если бы это требование не предъявлялось к системе DIALOGUE, в целом было бы желательно, чтобы подсистема обмена обладала этим полезным свойством.
Предполагается также, что при обмене длина сообщений никогда не превышает размера полного экрана, а при отображении текст берется из буферов, емкость которых определяется этой же величиной.
Модульность
. Основной смысл разбиения системы на модули заключается в том, чтобы локализовать и изолировать влияние возмущающих воздействий или изменений. Существуют различные типы
модульности в зависимости от того, какого рода возмущения или изменения рассматриваются.
Например, модульность, которая облегчает внесение изменений в систему, можно охарактеризовать как гибкость. Этот тип модульности имеет место в тех случаях, когда система спроектирована так, что изменение одного из требований приводит к необходимости корректировки лишь небольшого числа модулей (желательно только одного). Если модульная структура системы такова, что ее отдельные модули могут быть реализованы различными программистами практически независимо друг от друга, то имеет место конструктивная модульность. Модульность, при которой в системе локализуется влияние различных событий, происходящих в реальном масштабе времени (например, ошибок функционирования), называется событийной модульностью. Если внесение изменений в аппаратуру не требует модификации программного обеспечения системы, то это свойство системы называется прозрачностью.
И наконец, мы упомянем о функциональной модульности, обеспечивающей обозримость программ. В этом случае система разбивается на легко обозримые части с четко определенным набором функций. Необходимость в разбиении системы на модули по этому принципу может появляться даже тогда, когда другие критерии этого не требуют.
Несомненно, можно определить и другие типы модульности, но для наших целей вполне достаточно приведенных выше критериев.
Прежде чем рассмотреть подсистему СОММ в аспекте модульности ее структуры, обсудим способы определения и оценки степени модульности системы.
Степень модульности
Согласно Майерсу [6], степень модульности можно определять по двум критериям — прочности и сцеплению. Каждому из этих критериев соответствует некоторое разбиение на классы, позволяющее оценивать модульность системы количественно.
Ниже перечислены введенные Майерсом классы модульной прочности в порядке убывания характеризуемой ими степени модульности.
Функциональная или информационная прочность существует в тех случаях, когда можно считать, что модуль реализует одну функцию коллективного использования или когда в его основе лежит какой-либо общий принцип, совместно используемые данные или ресурс. ■
Коммуникационная прочность возникает тогда, когда все функции модуля связаны по данным последовательно (например, одна функция обрабатывает выход другой).
Процедурная прочность существует в тех случаях, когда последовательность выполнения функций модуля определяется внешними событиями (например, одна функция должна быть выполнена по времени раньше другой).
Логическая прочность появляется тогда, когда имеется единственная точка входа в модуль, выполняющий множество функций.
Случайная модульность существует в тех случаях, когда между функциями модуля отсутствуют какие бы то ни было связи.
Майерс приводит также следующие семь типов модульного сцепления в порядке убывания характеризуемой ими степени модульности:
отсутствие сцепления;
сцепление по данным через однородные параметры;
сцепление по формату через неглобальную структуру данных;
сцепление по управлению, когда один модуль управляет извне внутренней логикой работы другого модуля;
сцепление по внешним данным через однородные глобальные параметры;
сцепление по общим данным через структурированные глобальные параметры;
сцепление по содержимому через внутренние ссылки между функциями модуля.
Типы прочности и сцепления модулей, перечисленные выше, приведены здесь главным образом для того, чтобы дать читателю представление о понятиях, ассоциируемых с критериями модульности. Хотя в дальнейшем эта классификация явным образом использоваться не будет, ее влияние будет сказываться неявно при выборе конкретного проектного решения из многих возможных.
Перед тем как обратиться к построению подсистемы СОММ, рассмотрим связи между указанными классами прочности и сцепления модулей, с одной стороны, и предыдущими примерами проектирования, описанными в гл. 4,— с другой.
В системе LIFE (гл. 4) отсутствует свойство гибкости по отношению к изменениям, вносимым в команды оператора, поскольку в результате требуется модификация двух модулей, а именно модуля приема строки символов и модуля декодирования командных строк. Каждый из них имеет высокую функциональную и информационную прочность; помимо этого они слабо сцеплены посредством небольшого числа параметров, один из
которых—это код слова, извлекаемый из словаря в одном модуле и используемый в другом для декодирования цепочек слов. При внесении изменений в структуру команд должны модифицироваться как словарь, так и таблицы, определяющие правильную последовательность слов в строках, т. е. возникает необходимость коррекции двух модулей. Как уже отмечалось в гл. 4, указанную трудность можно обойти путем объединения двух модулей в один — модуль декодирования командных строк и символов; при этом функциональная и информационная прочности остаются высокими. Таким образом, в соответствии с критериями Майерса система, полученная в результате удаления компоненты, реализующей межмодульное сцепление, обладает более высокой степенью модульности, чем исходная. Конечно, увеличение степени модульности системы посредством объединения модулей имеет предел, который достигается в том случае, когда теряется функциональная или информационная прочность или же когда программа становится чрезмерно запутанной.
Примером системы, обладающей высокой степенью событийной модульности, является система DIALOGUE, описанная в гл. 4. Реакция ее на все события, связанные с действиями оператора, включая выдачу команд, уведомление об исполнении команд, регистрацию системных ошибок и т. п., обеспечивается единственным модулем дешифратора событий. Последний имеет высокую функциональную и информационную прочность и не нуждается во взаимодействии с другими модулями для корректной реакции на события.
Подсистема СОММ с точки зрения модульности
Мы вынуждены отложить принятие некоторых проектных решений до тех пор, пока не рассмотрим проблему надежности (разд. 6.4), но уже сейчас можно сделать первые шаги в проектировании подсистемы СОММ, основываясь только на принципе модульности.
В разрабатываемой нами подсистеме существует иерархия данных, которая определяет соответствующую иерархическую многоуровневую структуру модуля. На верхнем уровне подсистема СОММ имеет дело с сообщениями, которые представляют собой символьные строки переменной длины, поступающие из памяти терминала рабочей станции, а на нижнем оперирует с символами, пересылаемыми по линии связи. Используя метод проектирования «от границ—внутрь», описанный в гл. 4, можно получить в результате модуль с одноуровневой структурой /рис. 6.1, а). На этом рисунке схематически изображен один
СообщенияСообщенияСообщенияСообщенияСообщенияСообщения(а) Один уровень.(а) Один уровень./в/ Три уровня./в/ Три уровня.(б) Два уровня(б) Два уровняРис. 6.1. Возможные многоуровневые структуры подсистемы СОММ.Рис. 6.1. Возможные многоуровневые структуры подсистемы СОММ.
Сообщения
Сообщения
Сообщения
Сообщения
Сообщения
Сообщения
(а) Один уровень.
(а) Один уровень.
/в/ Три уровня.
/в/ Три уровня.
(б) Два уровня
(б) Два уровня
Рис. 6.1. Возможные многоуровневые структуры подсистемы СОММ.
Рис. 6.1. Возможные многоуровневые структуры подсистемы СОММ.
модуль обмена М, оперирующий сообщениями на верхнем уровне и символами — на нижнем.
Однако по ряду причин удобно разбивать сообщения на промежуточные блоки данных фиксированной длины, которые будем называть кадрами. Нетрудно понять, что в первую очередь это желательно сделать для увеличения надежности, поскольку отказ аппаратуры во время передачи одного кадра приведет только к необходимости повторной передачи этого же кадра, а не всего сообщения. Ниже приведен ряд дополнительных важных доводов в пользу введения кадров:
управление буферами обмена упрощается, если их размер соответствует фиксированной длине кадров;
синхронизация передачи и приема осуществляется легче в случае кадров фиксированного размера;
свойство прозрачности модуля является, по-видимому, более достижимым, поскольку устройства обмена оперируют кадрами данных фиксированного размера.
Кадры образуют новый промежуточный уровень в иерархии данных; на рис, 6.1,6 изображена двухуровневая структура мо-
дуля, в которой между модулем обмена сообщениями М и аппаратурой помещен модуль обмена кадрами. Можно предположить, что он будет не только отслеживать правильность физической организации кадра, но и выполнять логические функции, связанные с восстановлением информации в случае отказа сети. Вследствие вышеизложенного представляется разумным разделить модуль обмена кадрами на два уровня, как показано на рис. 6.1, в,— модуль логического обмена F, выполняющий только функции планирования порядка обмена и устранения ошибок, и модуль физического обмена Р, осуществляющий только фактическую передачу и прием данных.
С точки зрения модульности структура, изображенная на рис. 6.1, в, имеет ряд преимуществ:
каждый модуль обладает (при правильном проектировании) высокой функциональной прочностью и слабым сцеплением с остальными модулями системы;
функциональная модульность потенциально очень высока, поскольку каждый правильно спроектированный модуль будет выполнять четко определенные функции и иметь понятную спецификацию;
событийная модульность, по-видимому, тоже высока, так как каждый модуль реагирует только на вполне определенное множество событий, однозначно связанных с выполняемой им функцией (модуль обмена сообщениями реагирует на события, относящиеся лишь к обработке всего сообщения; модуль логического обмена выполняет функцию планирования порядка обмена и реагирует на отказы линии связи при передаче кадров; модуль физического обмена осуществляет фактический прием и передачу кадров);
можно надеяться, что вся подсистема в целом окажется в достаточной степени прозрачной, так как в случае необходимости модули нижнего уровня можно спроектировать таким образом, что они легко могут быть заменены специальными кристаллами.
Если в нашем проекте мы остановимся на многоуровневой структуре, то при модульном построении системы появятся проблемы, связанные с различными способами организации связи модулей. На рис. 6.2 схематически изображены возникающие при этом потоки данных: рис. 6.2, а соответствует случаю, когда модули сцеплены непосредственно; на рис. 6.2, б связь осуществляется косвенно через интерфейсные модули; на рис. 6.2,в представлена противоположная ситуация, когда сцепление модулей выполняется централизовано через управляющий модуль, реализующий все интерфейсы между уровнями,
(в) Косвенное сцепление через модуль управления системой, ”(в) Косвенное сцепление через модуль управления системой, ”
(в) Косвенное сцепление через модуль управления системой, ”
(в) Косвенное сцепление через модуль управления системой, ”
Рис. 6.2. Принципы межуровневого сцепления — представление информационного потока.
Вообще модули, соответствующие уровням, изображенным на рис. 6.2, могут быть описаны на языке Ада как активные или пассивные пакеты. Поэтому в связи с тем, что временная последовательность событий, отражающих функционирование уровней в направлениях «снизу — вверх» и «сверху — вниз», вообще говоря, непредсказуема, можно ожидать, что реализация модульной структуры, представленной рис. 6.2, а и 6.2, б, потребует организации множества задач внутри модулей каждого уровня, т. е. пакеты будут активными. Способ обеспече-
Условные обозначения;
Т - задача-курьер * М - ведущая задача.
Рис. 6.3. Прямое нисходящее сцепление уровней.
ния модульности, иллюстрируемый рис. 6.2, в, основан на том, что в системе существует управляющий пакет, который проводит необходимое упорядочение; поэтому программные пакеты, реализующие функции различных уровней системы, сами могут быть пассивными.
Что можно сказать о структуре всей системы? Для определе-
ния порядка обработки потоков данных, схематически показанных на рис. 6.2, рассмотрим структурные графы, отображающие различные типы сцепления между пакетами (рис. 6.3—6.5).
Вообще организация прямого сцепления модулей может допускать несколько различных структурных форм: либо однонаправленные нисходящие вызовы процедур следующего уровня (рис. 6.3), либо «взаимные» обращения сцепленных пакетов друг к другу, осуществляемые в обоих направлениях (рис. 6.4). Мы назовем эти две формы связи пакетов нисходящей и симметричной схемами взаимодействия.
Нисходящая схема взаимодействия пакетов, изображенная
ПЕРЕДАЧА ПРИЕМ ПЕРЕДАЧА ПРИЕМ ПЕРЕДАЧА ПРИЕМ
fa) Интерфейсное(б) Внутренняя структура системы (в) Внутренняя структура
Представление.при наличии задач-курьеров. v системы с использованием
" буферизующих задач.
Условные обозначения:
Т - задача-курьер;
8 - буферизующая задача;
М - ведущая задача уровня.
Рис. 6,4, Прямое симметричное сцепление уровней.
на рис. 6.3, особенно привлекательна, поскольку, во-первых, хорошо знакома, а во-вторых, ее применение предотвращает возникновение тупиков из-за неосторожного использования «взаимных» вызовов активными пакетами; кроме того, она легко понятна программистам, не знакомым с параллельными системами. Каждый пакет, реализующий функции некоторого уровня системы в соответствии с терминологией гл. 3, может быть охарактеризован как агент. Он принимает вызовы от верхних уровней, и сам в свою очередь обращается к нижним уровням; при этом вызовы в обратном направлении отсутствуют. Передача информационных объектов как сверху — вниз, так и снизу—вверх всегда инициируется верхним уровнем путем вызова некоторой процедуры нижнего уровня, причем во втором случае эта процедура ожидает поступления данных «снизу».
Симметричная схема взаимодействия пакетов, представленная на рис. 6.4, наоборот, менее известна и поэтому может затруднить неопытному программисту понимание деталей функционирования системы. Более того, ее применение увеличивает опасность, возникновения тупиков в зависимости от внутренней структуры пакетов.
На рис. 6.3, б, 6.4, б, в показано, каким образом канонические схемы взаимодействий задач, описанные в гл. 3 и изображенные на рис. 3.21, связаны со схемами взаимодействия непосредственно сцепленных пакетов, приведенными на рис. 6.3, а и 6.4, а соответственно. Использование задачи, осуществляющей двойную транспортировку данных (рис. 3.21,6), приводит либо к нисходящей, либо к симметричной схеме взаимодействий, а в случае применения буферизующей задачи (рис. 3.21, з) получается симметричная структура взаимодействий пакетов. Таким образом, выбор между нисходящей (рис. 6.3, а) и симметричной (рис. 6.3, б) схемами зависит не только от внешних требований к пакетам, но основывается также и на компромиссе между возможными внутренними структурами. Как уже отмечалось в гл. 3, применение задач-курьеров обеспечивает условия для более гибкого подхода к внутреннему структурированию системы, чем использование буферизующей задачи, но требует порождения большого числа задач и может быть несколько менее эффективным (хотя в обоих случаях необходимо одинаковое число рандеву для передачи данных). Если применяется первый метод, то число задач может быть уменьшено при использовании единственной задачи-курьера для организации приема информации (рис. 3.18, г); реализация обращений для передачи данных возлагается при этом на задачи управляющего уровня. Однако анализ требований, предъявляемых в данном случае к блоку управления информационным потоком, показал, что такой подход непригоден для использования, поскольку при этом за-
дача основного уровня должна ожидать разрешения на передачу данных от нижнего уровня (см. рис. 3.22,6), блокируя таким образом прием вызовов, поступающих «сверху». Отсюда следует, что при организации взаимодействий с использованием задач-курьеров необходимо иметь две такие задачи, а не одну.
На рис. 6.5 изображены различные схемы, иллюстрирующие принцип косвенного сцепления модулей. На рис. 6.5, а каждый уровень представлен в виде активного головного пакета, имеющего к тому же отдельные интерфейсные пакеты для доступа к вышестоящему и нижестоящему уровням системы. Эта структура обладает меньшей степенью модульности, чем структуры, рассмотренные ранее, так как ни в одном из пакетов задаваем
(а) Независимые уровни,
сцепленные через обслужИ0Э19Щ^ М9Дули,
(б) Обслуживающие пакеты различных уровней,' сцепленные посредством транспортировочных пакетов или управляющего модуля,
Рис, 6.5. Способы косвенного сцепления уровней.
мый процедурами интерфейс не определен, и в результате смысл назначение каждого пакета становятся менее понятными. Система, спроектированная таким образом, имеет более высокую степень сцепления, чем системы, изображенные на рис. 6.3 и 6.4, поскольку она разбита на большее число модулей и как следствие в ней имеется больше межмодульных связей при том же диапазоне функциональных возможностей; менее понятна и ее общая структура управления.
На рис. 6.5, б изображена еще одна возможная схема косвенного сцепления модулей; она образуется либо только активными пакетами без специального блока управления, либо пассивными пакетами и главным управляющим модулем. В любом случае передача данных между уровнями осуществляется без использования собственных процедур пакета. Это происходит потому, что в языке Ада описания процедур пакета конкретного уровня, доступных «сверху» и «снизу», сосредоточены в единой спецификации интерфейса. В результате процедуры, используемые на нижестоящем уровне, видимы для вышестоящего, и наоборот. Описанная структура также обладает меньшей степенью модульности, чем структуры, представленные на рис. 6.3 и 6.4.
Основываясь на результатах предыдущего обсуждения концепции модульности, при проектировании подсистемы СОММ мы остановимся на следующих предварительных решениях:
реализовать трехуровневую структуру, иллюстрируемую < рис. 6.1, в;
использовать схему прямого сцепления модулей, изобра- ' Женную на рис. 6.2, а, 6.3 или 6.4.
' Как уже отмечалось выше, выбор конкретного типа сцепления модулей (рис. 6.3 и 6.4) далеко не очевиден. С целью достижения большей наглядности мы выбрали (несколько произвольно) нисходящую схему взаимодействий (см. рис. 6.3). Задача реализации симметричной схемы (рис. 6.4) предлагается читателю в качестве самостоятельного упражнения (при этом следует иметь в виду, что принципиальное отличие от подхода, принятого выше, иллюстрирует только рис. 6.4, в).
Приняв принцип многоуровневого построения системы, мы должны быть особенно осторожны в обращении с терминологией при описании прохождения потока данных между уровнями. С общесистемной точки зрения можно считать, что данные перемещаются сверху—вниз при передаче и снизу — вверх при приеме; в первом случае их можно называть исходящими, а во втором — входящими. Во избежание путаницы термины передача, прием, исходящий поток и входящий поток будут использоваться в дальнейшем только в этом широком системном смысле, а не для указания направления движения информации через границы уровней; только термины «сверху — вниз» и «снизу — вверх» могут применяться в любых контекстах без ограничений. Например, «входящие данные» могут двигаться как в направлении данного уровня, так и от него; при этом подразумевается, что поток данных либо поступает на некоторый уровень «снизу», либо движется извне по направлению «снизу — вверх».
Надежность
В данном разделе обсуждается проблема надежности в свете технических требований к подсистеме СОММ. Как мы увидим ниже, решение этой проблемы может быть получено главным образом при проектировании системы на уровне потоков данных. Поэтому рассматриваемые далее вопросы в основном никак не связаны с использованием языка Ада как языка проектирования.
Прежде чем непосредственно обратиться к основной теме раздела, рассмотрим природу возникающих в системе неисправностей и ошибок, а также механизмы их обнаружения и устранения. Неисправность — это нарушение нормального функционирования системы, вызывающее ошибку, наблюдаемую в определенных условиях работы, которая в свою очередь может приводить к полному отказу системы, частичному отказу или вообще никак не проявляться в зависимости от реализованных методов обнаружения и устранения ошибок. Неисправности могут быть результатом ошибок проектирования и конструирования системы или могут неизбежно возникать во время ее функционирования по следующим причинам:
вследствие ошибок человека, включая
неправильные команды или неверные ответные действия;
неправильные данные;
из-за отказов канала связи, приводящих к
искажению данных,
потере данных,
дублированию данных;
из-за отказов компонентов системы, включая
отказ процессора,
отказ линии связи,
отказ какого-либо устройства, '
отказ узла надежности.
. Наше рассмотрение неисправностей и ошибок будет основываться в этой главе на предположении, что объединенная система DIALOGUE/СОММ является единым узлом надежности (см. гл. 5). Таким образом, при анализе проблемы надежности мы ограничимся обсуждением внутренней логической корректности объединенной системы DIALOGUE/СОММ и вопросов обнаружения и устранения ошибок, возникающих при функционировании системы.
Мы не будем рассматривать возможность появления внутренних ошибок функционирования в подсистеме СОММ, поскольку приняли выше предположение о существовании единого узла надежности.-'
Использованный буфер ТХDIALOGUEИспользованный буфер ТХDIALOGUEТХ MSGТХ MSGИсходныйИсходныйбуфер RXбуфер RXсоммсоммУправлениеобменомсообщениямиУправлениеобменомсообщениямиКадрДанныхКадрДанныхRXRXТХТХКадр данныхКадр данныхНемодный буфер ТХНемодный буфер ТХУправлениелогическимобменомкадрамиУправлениелогическимобменомкадрамиИспользованный буферахО|Квитированный ТХ (или отвергнутый RX)Использованный буферахО|Квитированный ТХ (или отвергнутый RX)Пул свободных\ кадровых )В ч буферов УПул свободных\ кадровых )В ч буферов У
Использованный буфер ТХ
DIALOGUE
Использованный буфер ТХ
DIALOGUE
ТХ MSG
ТХ MSG
Исходный
Исходный
буфер RX
буфер RX
сомм
сомм
Управлениеобменомсообщениями
Управлениеобменомсообщениями
Кадр
Данных
Кадр
Данных
RX
RX
ТХ
ТХ
Кадр данных
Кадр данных
Немодный буфер ТХ
Немодный буфер ТХ
Управлениелогическимобменомкадрами
Управлениелогическимобменомкадрами
Использованный буферах
О|
Квитированный ТХ (или отвергнутый RX)
Использованный буферах
О|
Квитированный ТХ (или отвергнутый RX)
Пул свободных\ кадровых )В ч буферов У
Пул свободных\ кадровых )В ч буферов У
Корректность внутренней логики подсистемы
Буферизация при обмене данными является той частью подсистемы СОММ, проектирование и реализация которой сопряжены с наибольшим количеством ошибок. На рис. 6.6 представлен возможный граф потоков данных, поступающих в буфер обмена. На этом рисунке изображены модуль обработки событий Е и модули М, F, Р, описанные ниже. Кроме того, отдельно показаны модули S и В, осуществляющие управление пулом буферов визуальных сообщений и пулом кадров данных соответственно; в пулах имеются предварительно выделенные группы
Условные обозначения:
О—* ’заполненные буферы О►- свободные буферы
Пул буферовл.экранных j sсообщений у
Кадрданных(копия)Кадрданных(копия)КадрданныхКадрданныхИсходный буфер RXИсходный буфер RX
Кадрданных(копия)
Кадрданных(копия)
Кадрданных
Кадрданных
Исходный буфер RX
Исходный буфер RX
Управлений физическим.
обменом кадрами
Рис. 6.6. Поток кадров данных в подсистеме СОММ с совместно используемыми буферными пулами.
буферов фиксированного размера, используемых различными модулями подсистемы.
Рис. 6.6 соответствует предположению о том, что кадры данных сохраняются в буферах обмена для осуществления повторной передачи до тех пор, пока не поступит подтверждение об их приеме. Это предположение естественным образом следует из рассуждений, которые привели нас к введению понятия кадра в разд. 6.2.
Рассмотрим сначала рис. 6.6 в аспекте буферизации кадров данных. Этот процесс можно описать следующим образом: при передаче данных свободные буферы движутся из пула В в управляющий модуль обмена сообщениями М, где они заполняются соответствующей информацией. Затем эти буферы пересылаются в модуль логического обмена кадрами данных F для передачи, а модуль F в свою очередь направляет их модулю Р, реализующему физический уровень обмена. После завершения обмена управление заполненными буферами опять переходит к модулю F на случай возможной повторной передачи. В конце концов после сигнала подтверждения приема кадров данных модуль логического обмена F возвращает свободные буферы в пул В. Когда осуществляется прием данных, свободные буферы поступают из пула В в управляющий модуль физического обмена кадрами Р, где они будут заполнены входящими данными. Заполненные буферы движутся снизу—вверх и в конечном счете передаются обратно в пул В модулями, реализующими более высокие уровни иерархии.
Перейдем теперь к рассмотрению процесса буферизации сообщений. В гл. 4 неявно предполагалось существование единственного буфера дисплея (этот буфер занимает как раз ту часть памяти терминала, в которой содержится сообщение, выводимое на экран), и поэтому вопрос буферизации полностью игнорировался. Однако в общем случае можно использовать группу буферов сообщений S (объем одного буфера равен размеру экрана), каждый из которых может выбираться программным способом для заполнения данными, отображаемыми на экране.
На рис. 6.6 схематически изображен поток сообщений, поступающих в пул и извлекаемых из пула S. Модуль Е получает свободные буферы из S как для передачи, так и для приема сообщений: при передаче заполненный буфер сообщений из модуля Е копируется модулем М в буферы кадров, а затем пересылается обратно в Е; при приеме свободный буфер из модуля Е заполняется информацией, а затем возвращается обратно.
Источниками возможных ошибок при проектировании и реализации системы в соответствии с рассмотренными принципами могут служить множественность ссылок (aliasing), т. е. существование нескольких копий ссылочной переменной, указывающих
на- один и тот же буфер, и тупики, возникающие вследствие состязания за получение свободных буферов и управления потоком заполненных буферов между модулями.
Множественность ссылок. Вопроса множественности ссылок '(смешения имен) мы коротко уже касались в гл. 5. Для предотвращения этой ситуации в некоторых случаях там был предложен метод перераспределения идентификаторов. Однако для целей данной главы этот вопрос необходимо обсудить подробнее.
Используя рис. 6.5, а, «размножение» ссылок можно объяснить следующим образом. Предположим, что модули передают друг другу указатели (ссылочные переменные) буферов. Очевидно, что при работе системы могут возникать ситуации, когда несколько модулей будут обладать копиями ссылки на один и тот же буфер, хотя при правильном функционировании только один модуль может иметь право использовать такую ссылку в данный момент. Ада и другие аналогичные языки не запрещают использовать эту ссылку тогда, когда другой модуль обладает ее копией. При проектировании системы эту языковую возможность можно реализовать на основе требования, чтобы модуль, временно владеющий копией ссылки, уничтожал ее, когда отпадет необходимость в ее использовании; «исходный владелец» указателя может затем использовать его повторно. Например, как видно из рис. 6.5, а, модуль физического обмена кадрами после передачи может уничтожить «свою» копию ссылки на буфер, если модуль логического обмена F сохраняет «оригинал» этой ссылки.
Проблема, возникающая при размножении ссылок, состоит в том, что небольшие ошибки при их использовании могут приводить к серьезным последствиям, причину которых обычно бывает трудно установить. Предположим, например, что подсистема СОММ отлаживалась снизу — вверх таким образом, что ошибочный модуль логического обмена тестировался совместно с правильными модулями физического обмена кадрами данных и управления пулом свободных буферов. Тогда вполне возможно, что дефектный модуль логического обмена в какой-то момент воспользуется старой копией ссылки на буфер, который уже находится в модуле физического обмена; в результате при работе правильного модуля возникает необъяснимая ошибка. Поскольку возможность применения метода размножения ссылок определяется на этапе проектирования, неизбежно появление ошибок, аналогичных указанной выше.
Тупики и локальное регулирование потока данных. Слово «локальный» используется здесь для того, чтобы различать состояния, возникающие внутри конкретной системы, подключенной к средствам связи, от состояний, появляющихся при взаи-
модействии различных систем, соединенных теми же средствами связи.
Различного рода блокировки потоков данных, изображенных на рис. 6.6, могут приводить к тупиковым ситуациям
в модуле, управляющем работой пула свободных буферов, из-за того, что этот пул пуст;
в любом другом модуле из-за невозможности обработки новых заполненных буферов (отказ от обработки в этом случае называется локальным регулированием потока).
Модуль может осуществлять локальное регулирование потока данных по некоторым вполне определенным внутренним причинам, например в результате достижения произвольно установленного при проектировании предела емкости пула или потому, что этого требует протокол обмена между равноправными модулями в независимых системах, объединенных общими средствами связи; такая ситуация будет рассматриваться ниже.
Блокировки потоков данных могут приводить к тупику и тогда, когда отдельные задачи в различных модулях оказываются блокированными в ожидании снятия блокировок потоков данных, т. е. возникает круговое ожидание и как результат — последующий неизбежный тупик.
Предотвращение тупиков, вызванных блокировками изображенных на рис. 6.6 потоков кадров данных, требует на уровне управления кадрами выполнения ряда условий:
Пул В должен содержать некоторое минимальное число пустых буферных блоков, достаточное для того, чтобы при передаче максимально использовать пропускную способность модуля логического обмена, и еще один буфер для приема информации. Меньшее число буферов может привести к тупику, если, например, все они находятся, в данный момент времени в модуле F, ожидающем получения подтверждающих прием сигналов, которые могут вообще не поступить при отсутствии свободных буферов. Заметим, что минимально возможное число буферов в пуле — два, что соответствует максимальной пропускной способности при передаче, равной емкости одного буфера.
Модуль физического обмена Р, перед тем как перейти в состояние ожидания поступления новой информации, должен всегда пересылать другому модулю принятый перед этим блок данных. Такая стратегия гарантирует, что в итоге хотя бы один пустой буфер будет возвращен в пул для использования при приеме, даже если все остальные будут связаны ожиданием подтверждения приема ■ информации.
Модуль обмена сообщениями М при передаче информации должен прекратить заполнение свободных буферов кадров фрагментами сообщений, как только модуль логического обмена F возьмет на себя регулирование пото- ' ка передаваемых сообщений (т. е. при достижении предела пропускной способности модуля F). Это препятствует возникновению ситуации, когда в буферном пуле В больше нет пустых буферов, требуемых для приема информации, а их появление невозможно из-за действующих блокировок. В противном случае, т. е. при отказе от вышеизложенной стратегии, поступающие подтверждения приема, которые должны были бы освободить буферные блоки в модуле F, могут оказаться заблокированными.
В основе этих условий отсутствия тупиковых ситуаций лежит допущение, что поток принимаемых кадров данных никогда не блокируется модулем обмена сообщениями М надолго и, следовательно, не препятствует возвращению буферов в пул В. Такое допущение может быть сделано только в том случае, если буферный пул терминальных сообщений S имеет как минимум ■ два буфера и если по крайней мере один из них всегда зарезервирован модулем М для приема данных. Тогда любая нехватка свободных буферов для приема сообщений всегда будет временным явлением.
Если вышеперечисленные условия не выполняются, то могут возникать самые разнообразные тупики. Например, одна из самых тяжелых по своим последствиям тупиковых ситуаций может складываться так, как описано ниже. Допустим, что при передаче достигнут предел пропускной способности модуля F в тот момент, когда модуль М копирует некоторое сообщение в буферные блоки для передачи. Предположим далее, что модулем Е заполнены остальные свободные буферы, в которые помещены сообщения оператора, или что в системе имеется всего один буфер. Тогда поток поступающих данных будет в конце концов заблокирован, поскольку отсутствие буфера для приема сообщения препятствует обратному проникновению принятых буферных блоков в пул В. Поэтому будет заблокирован поток сигналов, подтверждающих прием переданной информации; в результате возникнет полная блокировка как передачи, так и приема данных. Теперь вся система окажется в состоянии тупика! Но еще хуже то, что в результате тупика могут быть заблокированы две взаимодействующие системы, пытавшиеся одновременно переслать сообщения друг другу!
Мы использовали так называемый консервативный метод развязки тупиковых ситуаций. Другой, менее консервативный подход допускает ничем не ограничиваемое состязание за обла-
дание ресурсами при наличии защиты, обеспечиваемой механизмами предотвращения тупиков и устранения их последствий. Более глубоко с проблемой тупиков можно познакомиться, обратившись к какому-либо учебнику по операционным системам.
Механизмы локального регулирования потока данных. Как мы имели возможность убедиться, в любой многомодульной системе регулирование потока данных может осуществляться при межмодульных взаимодействиях. В гл. 3 обсуждались различные подходы к решению этой проблемы, включая и метод заблаговременной выдачи кредита на передачу. Суть этого подхода состоит в том, что отправитель не посылает адресату информацию до тех пор, пока не получит от него разрешения. Такой метод особенно удобен при наличии совместно используемого буферного пула, поскольку позволяет избежать эффекта связывания буферов, когда информационный обмен оказывается невозможным.
Самый прямой способ реализации этого метода в случае общего буфера состоит в том, что отправитель сообщения запрашивает у адресата свободный буфер для передачи данных. Такой механизм наиболее прост в тех ситуациях, когда получение разрешения на передачу информации зависит только от наличия свободного буфера. Взаимодействие систем DIALOGUE и СОММ является как раз примером такого рода — здесь кредит на передачу может иметь форму выделяемого свободного буфера.
Для организации более сложного межмодульного взаимодействия требуется, чтобы отправитель сообщения, перед тем как запрашивать свободные буферы для занесения в них информации, сначала получил разрешение на передачу одного или нескольких информационных объектов. Этот механизм удобнее в случаях, когда получение такого разрешения зависит еще и от доступности других ресурсов, а не только от наличия свободного буфера; иллюстрацией служит взаимодействие модулей Мир подсистемы СОММ. Например, в модуле F для хранения кадров данных, прием которых не подтвержден, отведена память фиксированного объема — независимо от числа доступных буферов. Как будет видно в подразд. 6.4.2, эта величина является параметром, зависящим от протокола обмена кадрами данных между равноправными модулями F, принадлежащими различным системам. Действительно, при взаимодействии с модулем М управление потоком передаваемых данных (блокирование) могло бы осуществляться модулем F даже при наличии свободных буферных блоков в пуле В.
До сих пор механизм получения кредита на передачу обсуждался только в аспекте обмена блоками прикладных данных
(в данном случае терминальными сообщениями или их фрагментами); поэтому на рис. 6.6 схематически показано движение лишь потока именно такой информации. Однако, как мы увидим далее, в подразд. 6.4.2, межмодульные потоки данных могут иметь смешанный характер и содержать не только прикладные данные, но и управляющую информацию, зависящую от структуры внутрисистемных протоколов. Например, при взаимодействии модулей F и Р некоторые кадры будут содержать только протокольные сообщения с такими функциями, как установление связи или (глобальное) управление межсистемным потоком кадров данных.
В тех случаях, когда межмодульный информационный поток в многоуровневой системе является смешанным, ее нижние уровни должны обрабатывать все компоненты потока одинаковым образом, так как не способны установить различие между ними. В противном случае было бы утрачено свойство многоуровневой модульности системы. Например, модуль Р должен обрабатывать все кадры данных, циркулирующие между Р и F, одинаково, поскольку он не может (и не должен) делать различия между прикладной и управляющей информацией. Различия между типами данных проявляются только на уровне модуля F. Это означает, что локальное управление потоком данных (при наличии смешанных межмодульных потоков) не может осуществляться выборочно применительно только к его прикладным компонентам.
Отсюда следует, что модуль F должен иметь собственный внутренний механизм распознавания того момента, когда необходимо прекратить пересылку адресату новых кадров данных, так как в модуле Р эта функция реализована быть не может. Нужный механизм может основываться на выделении ограниченного объема памяти для приема данных, о чем уже шла речь выше. Еще одним следствием смешанного потока данных является то, что модуль F не может избирательно «останавливать» поток информационных кадров, движущийся из модуля Р снизу — вверх, путем локального воздействия на интерфейс F/Р. Единственная возможность для осуществления в модуле F локального управления приемом информации — отвергнуть поступившие кадры данных.
В качестве последнего замечания по поводу механизмов локального регулирования информационного потока отметим, что в рамках управляющих структур разрешение на передачу одного элемента данных может быть получено отправителем неявно— при возврате из процедуры SEND или при вызове процедуры RECEIVE пакета, реализующего обмен. Следствием такого подхода является требование, чтобы внутренние задачи пакетов блокировали модули, обращающиеся к процедуре SEND,
или задерживали выполнение программ, вызывающих процедуру RECEIVE, до момента получения разрешения на обмен данными.
Использование протоколов обмена данными для обнаружения внешних ошибок функционирования и устранения их последствий
Протокол обмена данными представляет собой диалог между равноправными модулями одного логического уровня в различных системах, обеспечивающий надежное взаимодействие между ними. Для реализации надежного взаимодействия всех систем может потребоваться введение протоколов информационного обмена на нескольких уровнях. Протокол предусматривает обмен соответствующими протокольными сообщениями между равноправными модулями. Чтобы отличать эти протокольные сообщения от сообщений других типов, назовем их протокольными блоками данных (ПБД); это название соответствует терминологии, используемой специалистами, занимающимися стандартизацией протоколов. Ниже рассматриваются требования к протоколам различных уровней подсистемы СОММ.
Протоколы уровня управления обменом сообщениями. Проект нашей подсистемы учитывает только возможность временного отказа линии связи. Поэтому на данном уровне управления вполне достаточно рассчитывать на то, что оператор будет сам подтверждать прием сообщений (посылая ответы), сохранять копии передаваемых сообщений до момента получения подтверждения их приема, осуществлять их повторную передачу (в случае необходимости) и игнорировать возможное в связи с этим появление дубликатов сообщений. Выполнение всех этих функций не обязательно возлагать на специальный управляющий модуль. Другими словами, на уровне обмена сообщениями протокол не требуется вообще, а в задачи управляющего модуля должны входить лишь копирование сообщений и разбиение информационного потока на отдельные сообщения для обеспечения удобства распознавания конца входящего сообщения. Это может быть реализовано либо путем включения в информационную часть каждого передаваемого кадра заголовка, содержащего его номер, либо с помощью указателя числа кадров, помещаемого в информационную часть первого кадра, либо путем занесения признака конца сообщения в информационную часть последнего передаваемого кадра.
Протоколы уровня управления логическим обменом кадрами данных. Предыдущие рассуждения свидетельствуют о необходимости на этом уровне протокола, причем протокольные блоки
данных могут представлять собой либо кадры, включающие фрагменты передаваемой прикладной информации, либо управляющие кадры, не содержащие информации пользователя, но участвующие в процессе взаимодействия равноправных модулей управления логическим обменом. Для установления последовательности обмена данными и обнаружения ошибок требуется, чтобы все кадры были последовательно пронумерованы и предусматривали использование избыточных кодов, контролирующих ошибки. Кроме того, должна быть реализована возможность последовательной передачи нескольких кадров без ожидания квитирования каждого из них, что является необходимым условием осуществимости дуплексного режима работы.
Для увеличения эффективности информационного обмена пересылку квитирующих сигналов можно совмещать с передачей кадров данных в обратном направлении, а не посылать их отдельно. Это можно сделать, если присваивать каждому исходящему кадру данных два номера: один — при передаче (собственный порядковый номер кадра) и второй — при приеме (порядковый номер очередного ожидаемого кадра из входящего потока). Получение кадра данных с таким порядковым номером служит неявным уведомлением о приеме всех кадров с меньшими номерами. При задержке подтверждения отправитель может по истечении некоторого времени осуществить повторную передачу соответствующих кадров данных; для этого он должен хранить их копии вплоть до момента получения подтверждающего прием сигнала.
Управление потоком кадров может основываться также на идее определения максимально допустимого диапазона порядковых номеров кадров, для которых не получено подтверждение приема. Этот допустимый диапазон, называемый окном, и определяет необходимую емкость модуля F, упоминавшуюся ранее. В тот момент, когда число отправленных, но не квитированных, или принятых, но не обработанных кадров превышает размер окна, осуществляется регулирование исходящего или входящего потока соответственно. Оно выполняется без использования управляющих кадров: при передаче исходящий поток просто блокируется на время, пока окно буфера ТХ остается заполненным (это правило не касается кадров, передаваемых повторно); при приеме поступающие кадры данных просто отвергаются до тех пор, пока остается заполненным окно буфера RX. При таком подходе с точки зрения отправителя регулирование информационного потока дистанционным получателем не отличается от регулирования в случае отказа линии связи или узла сети; до тех пор пока оно продолжается, отправитель не получит подтверждений приема кадров данных, и его действия, связанные с повторной передачей, будут бесполезны.
Использование получателем управляющих кадров для уведомления отправителей информации о начале регулирования потока данных (RECEIVE-NOT-READY, К-ПРИЕМУ_НЕ_ГО- ТОВ) или о его завершении (RECEIVE-READY, К-ПРИЕМУ- ГОТОВ) повышает эффективность работы системы, поскольку предупреждает бесполезные повторные передачи информации и возможные ошибочные заключения о неисправности линии связи, возникающие в противном случае. Для упрощения изложения существа рассматриваемого проекта мы не будем останавливаться на анализе структуры управляющих кадров.
Таким образом, управляющие кадры в нашем примере используются только для первоначального установления связи, а поскольку их последовательная нумерация не требуется, необходимо индивидуальное квитирование каждого из них. При этом используются кадры двух типов: блок START (ЗАПУСК.) и блок START-ACK (ПОДТВЕРЖДЕНИЕ-ЗАПУСКА).
С учетом вышеизложенного требования к нужному нам протоколу обмена можно резюмировать следующим образом:
Кадры должны иметь фиксированный размер и в добавление к фрагменту сообщения содержать два порядковых номера (исходящий и входящий).
Порядковые номеры кадров данных должны вычисляться по модулю величины, равной размеру окна (известному заранее).
Локальное регулирование информационного потока должно осуществляться либо при передаче, либо при приеме данных в тех случаях, когда окно заполнено.
Подтверждением приема кадра данных должен служить присвоенный ему входящий порядковый номер, указывающий на очередной ожидаемый кадр, чем подтверждается прием всех предшествующих кадров; для посылки уведомления о том, что передача данных закончена, может быть использован кадр с нулевым номером.
» Для первоначального установления связи необходимо два ненумеруемых управляющих кадра (START и STARTACK).
> Предполагается, что работа системы состоит из двух этапов: начального запуска и передачи данных. На этапе начального запуска до передачи данных производится обмен управляющими кадрами START и START-ACK с целью подтверждения того, что оба оконечных устройства готовы к работе и линия связи исправна. На этапе передачи производится только обмен кадрами данных.
Для проверки правильности передачи кадров данных должны применяться избыточные коды, контролирующие ошибки.
Анализ протоколов обмена в подсистеме СОММ. Далее мы можем двигаться в двух направлениях: либо сначала разработать протоколы обмена данными (форматы ПБД, правила упорядочения, перечень состояний и т. п.), не приступая к непосредственному проектированию системы, либо сразу же начать с ее проектирования, а обращаться к деталям протоколов по мере появления вопросов, требующих разрешения. Мы остановимся здесь на втором подходе—методе пошаговой детализации, но попутно отметим, что в большинстве практических ситуаций при проектировании системы протокол обмена (если он нужен) чаще всего бывает задан и система должна конструироваться в точном соответствии с ним. Однако у нас уже достаточно информации для того, чтобы приступить к проектированию системы, не особенно вдаваясь пока в детали построения Протокола.
Данная ситуация несколько похожа на ту, которая встретилась нам в задаче упорядочения событий в гл. 4. Там мы разработали структуру всей системы, основываясь только на представлении о событиях, подлежащих обработке, а не на детальном знании состояний конечного автомата, осуществляющего обработку цепочек событий. .
Попробуем взглянуть на исходный граф потоков данных, изображенный на рис. 6.6, с более общих позиций и включим в него потоки между равноправными модулями различных систем, как показано на рис. 6.7.
На концептуальном уровне равноправные модули управления информационным обменом взаимодействуют друг с другом непосредственно через сообщения, появляющиеся на экране Дисплея, а равноправные модули управления логическим обменом кадрами данных — с помощью протокольных блоков данных (ПБД). Физически каждый из этих уровней взаимодействия реализуется системными модулями нижестоящего уровня.
На уровне модулей управления обменом сообщениями необходимо осуществлять только локальное регулирование потока информации и разделение его на сообщения. Очевидно, что эти функции могут быть реализованы в каждой отдельной системе введением локальных интерфейсов между модулями обмена сообщениями и модулями логического обмена кадрами данных, и не потребуют в явном виде дополнительного протокола обмена между равноправными модулями различных систем.
Выше уже указывалось на необходимость применения протоколов передачи данных и установления связи для организации взаимодействия равноправных модулей логического обмена кадрами данных. Однако только первый из указанных протоколов имеет непосредственное отношение к исходящему или вхо-
Условные обозначения:
О 1 ► фактический поток данных q^ концептуальный пот]ок данных
ПБД Протокольный блок данных
Система 1Система 2
Аппаратура физической линии связи
Рис. 6.7. Схема взаимодействия равноправных модулей в подсистеме СОММ, расположенных в различных узлах сети.
дящему информационному потоку управляющего модуля обмена сообщениями. Что же касается протокола установления связи, то он никак не затрагивает процесс обмена сообщениями, а имеет свои собственные автономные функции, выполнение которых приводит к формированию и восприятию специальных ПБД.
Теперь, приняв во внимание все вышеперечисленные соображения, мы можем продолжить проектирование нашей системы.
6.5. Рабочее проектирование подсистемы СОММ
В этом разделе мы проработаем детали проекта подсистемы СОММ на основе идей и решений, принятых в разд. 6.4. Сначала рассмотрим поток данных, а затем перейдем к синтезу структуры и внутренней логики подсистемы.
Информационный поток
На рис, 6.8 представлена схема, иллюстрирующая в информационном аспекте основные решения (как явные так и неявные), принятые в качестве отправных для более детального проектирования системы. При этом модули Е, М и F полностью соответствуют иерархической многоуровневой структуре, изображенной на рис. 6.3, б, с той лишь разницей, что модуль А! реализуется без использования задач, поскольку он является пассивным связующим звеном. Модуль Р служит драйвером ввода-вывода, и поэтому для выполнения присущих ему функций требуются две задачи, осуществляющие ввод и вывод данных. На рис. 6.8 уже показаны некоторые структурные элементы системы (пакеты и задачи), однако подробное обсуждение механизма их взаимодействия мы проведем несколько позже. Единственным важным недостающим элементом на этом рисунке является способ выдачи локального разрешения на обмен данными, реализуемый в интерфейсах M/F и F/P.
Интерфейс систем DIALOGUE и СОММ. В соответствии с результатами обсуждения, приведенными в подразд. 6.4.1, предполагается, что при взаимодействии систем DIALOGUE и СОММ в оперативной памяти имеются постоянно выделенные буферы для передачи и приема сообщений, а выдача разрешения на обмен сообщениями организована в рамках интерфейса DIALOGUE/СОММ путем предоставления свободных буферов.
Модуль дешифратора событий. Правила управления потоком буферов сообщений, иллюстрируемые рис. 6.8, можно кратко сформулировать следующим образом:
При начальном запуске системы модуль Е предоставляет свободный буфер модулю М для приема сообщений; затем после приема каждого сообщения и последующего освобождения экрана дисплея оператором модуль Е возвращает этот буфер модулю М.
Общая схема взаимодействий системы DIALOGUE с подсистемойОбщая схема взаимодействий системы DIALOGUE с подсистемойРис. 6.8.СОММ.Рис. 6.8.СОММ.
Общая схема взаимодействий системы DIALOGUE с подсистемой
Общая схема взаимодействий системы DIALOGUE с подсистемой
Рис. 6.8.
СОММ.
Рис. 6.8.
СОММ.
При нажатии оператором клавиши SEND модуль Е пересылает заполненный буфер модулю М для передачи по линии связи; после того как модуль М скопировал сообщение в буферные блоки обмена кадрами, он возвращает исходный буфер модулю Е для повторного использования.
Правила, приведенные выше, довольно консервативны, но вполне пригодны для решения поставленной задачи. В некоторых
случаях эти правила могут быть причиной замедленной работы системы: например, они не позволяют освобождать неиспользуемый буфер ТХ для приема модулем М нового сообщения, когда предыдущее еще сохраняется на экране дисплея. При этих обстоятельствах поступающее сообщение будет временно задержано.
С точки зрения оператора модуль Е расширяет возможности получения кредита на передачу информации: когда оператор запрашивает разрешение, нажимая клавишу RESERVE (РЕЗЕРВИРОВАНИЕ), то, начиная с этого момента (при условии, что буфер ТХ свободен), экран становится доступным ему для ввода сообщения; когда оператор нажимает клавишу SEND (ПЕРЕСЫЛКА), модуль Е блокирует выдачу соответствующего разрешения до тех пор, пока вновь не освободится буфер ТХ.
Мы предполагаем, что в любой момент времени модуль Е имеет возможность выводить на экран дисплея сообщение из любого требуемого буфера. Как на рисунке, так и в нашем обсуждении для простоты ряд деталей этого механизма опущен.
Управляющий модуль обмена сообщениями М. Этот управляющий модуль не реализует никакого протокола равноправного обмена. Его задачами являются только обеспечение подсистемы СОММ внутренним служебным интерфейсом, а также копирование, передача и прием сообщений при посредничестве служебных интерфейсов управляющего модуля логического обмена кадрами и модуля, организующего доступ в пул свободных буферных блоков.
Применительно к модулю М правила управления потоком сообщений и буферных блоков могут быть интерпретированы следующим образом:
модуль М получает буфер ТХ, заполненный сообщением, поступившим от модуля Е в момент времени, определяемый Е;
модуль М возвращает освободившийся буфер модулю Е после копирования сообщения в буферные блоки для передачи;
модуль М получает свободный буфер RX для приема сообщений при начальном запуске системы;
после того как произведено копирование последнего кадра поступившего сообщения в буфер RX модуль М направляет его модулю Е;
в момент времени, определяемый модулем Е, освободившийся буфер RX поступает обратно из Е в модуль М;
модуль М направляет кадры, заполненные данными, модулю F только при получении от F разрешения па передачу в форме предоставления свободного буфера ТХ;
кадры, заполненные данными, поступают в модуль М из F тогда, когда эти кадры доступны, и модуль М готов к их приему.
Управляющий модуль логического обмена кадрами данных. Модуль логического обмена кадрами, помимо функций служебного интерфейса, реализует два протокола управления равноправными модулями. Протокол начального запуска системы и протокол информационного обмена никогда не активизируются одновременно и поэтому могут быть реализованы с помощью единственной задачи FS. В системе предполагается также, что оператор не имеет возможности непосредственно запускать стартовый протокол, вводя команды с клавиатуры терминала. Этот протокол активизируется только при включении системы. В системе имеется некоторый управляющий модуль (не показанный на схеме рис. 6.8), который «отвечает» за запуск стартового протокола. Вообще при проектировании можно было бы потребовать, чтобы в распоряжении оператора имелись директивы, позволяющие ему с клавиатуры терминала выключать и запускать заново аппаратуру связи при подозрении на временный отказ линии или на выход из строя удаленной ЭВМ, которая подлежит замене на резервную. Эти функциональные возможности не будут включены нами в проект рассматриваемой системы, но при желании могут быть введены дополнительно без всяких затруднений.
Согласно рис. 6.8, задача FS «встраивает» кадры с управляющей информацией в исходящий поток данных и удаляет их из входящего потока без какого-либо взаимодействия с модулем вышестоящего уровня. Схема, изображенная на этом рисунке, соответствует предположению о том, что для пересылки управляющих кадров свободные буферы не используются. Предоставление буферов небольшого объема под управляющие кадры обеспечивается управляющим модулем логического обмена; эти буферы используются в циклическом режиме. Локальный механизм разрешения обмена информацией между модулями F и Р гарантирует, что управляющие буферы не будут повторно использоваться в F до тех пор, пока работа с ними не будет закончена в модуле Р.
Управляющий модуль физического обмена данными. Вследствие принятого нами проектного решения, в соответствии с которым допускается размножение указателей буферов, управление буферами исходящих кадров данных пока продолжает осуществлять модуль F. Поэтому по окончании передачи всех символов, заполнявших буфер, модуль Р просто «забывает» о том, что он когда-то имел к нему доступ.
Если при приеме информации проверочный код кадра указывает на ошибку, то принятые кадры могут рассматриваться
как недействительные, а освобождающиеся при этом буферы могут возвращаться модулю, осуществлявшему их прием. .
Структура и логика системы
Структурные схемы, разрабатываемые в этом разделе, основываются на требованиях к информационному потоку, изложенных в соответствующих частях подразд. 6.5.1.
В дальнейшем, как было определено в гл. 5, мы будем рассматривать только линейные схемы взаимодействия.
Модифицированный интерфейс систем. Исходную схему модуля дешифратора событий системы DIALOGUE, изображенную на рис. 4.31 и 4.32, теперь следует изменить с учетом ранее не рассматривавшихся возможностей буферизации данных и условий управления информационным потоком. Новая схема приведена на рис. 6.9. Ввиду того что вызов процедуры SEND из пакета М влечет за собой для инициатора вызова потенциально большое условное время ожидания конца копирования всего сообщения в буферные блоки, между модулем дешифратора событий и данной процедурой необходимо ввести как промежуточный уровень задачу ЕТХ, осуществляющую транспортировку информации при передаче. Ранее задача, выполнявшая аналогичную функцию при приеме, была обозначена как ERX.
Вышеупомянутый вход PUT-MSG (ПОМЕСТИТЬ_СО- ОБЩЕНИЕ) дешифратора событий (Е) получает теперь имя PUT. Он обеспечивает передачу входных сообщений без временных задержек. Три новых входа задачи Е указывают на точки синхронизации, в которых задачи ЕТХ и ERX, осуществляющие перенос данных, могут ожидать исходящего сообщения (вход GET), уведомлять о завершении передачи сообщения с одновременным возвратом освободившегося буфера ТХ (вход RETURN) и захватывать освобожденный буфер RX (вход PICKUP).
Задача Е предоставляет свободный буфер модулю М при начальном запуске системы через вход PICKUP и сразу после освобождения оператором буфера RX, который содержал выданное на экран сообщение.
В теле задачи ЕТХ реализуется цикл, в котором ожидание сообщения осуществляется путем вызова входа E.GET, посылка сообщения — путем обращения к входу M..SEND, а получение уведомления о завершении передачи и возврат освободившегося буфера — путем вызова Е.RETURN.
Тело задачи ERX в свою очередь тоже представляет собой цикл, в котором ожидание освобождения буфера организуется путем вызова входа Е.PICKUP, передача абоненту указателя
Условные обозначения:
О”* заполненные буферы
О" >- свободные буферы
Поток символов, считываемыхПоток символов, считываемыхс клавиатурыс клавиатурыЗадача дешифратора событий ЕЗадача дешифратора событий ЕСОММСОММВход закрыт до тех лор, пока не будет свободного буфера RXВход закрыт до тех лор, пока не будет свободного буфера RXВход закрыт, пока не будет заполненного буфера ТХВход закрыт, пока не будет заполненного буфера ТХВызывающий модуль ожидает завершения копирования сообщения в буферы кадров; по окончании передачи осуществляется возврат освободившегося буфераВызывающий модуль ожидает завершения копирования сообщения в буферы кадров; по окончании передачи осуществляется возврат освободившегося буфераВызывающиймодуль ожидает поступления сообщенияВызывающиймодуль ожидает поступления сообщенияDIALOGUEDIALOGUE
Поток символов, считываемых
Поток символов, считываемых
с клавиатуры
с клавиатуры
Задача дешифратора событий Е
Задача дешифратора событий Е
СОММ
СОММ
Вход закрыт до тех лор, пока не будет свободного буфера RX
Вход закрыт до тех лор, пока не будет свободного буфера RX
Вход закрыт, пока не будет заполненного буфера ТХ
Вход закрыт, пока не будет заполненного буфера ТХ
Вызывающий модуль ожидает завершения копирования сообщения в буферы кадров; по окончании передачи осуществляется возврат освободившегося буфера
Вызывающий модуль ожидает завершения копирования сообщения в буферы кадров; по окончании передачи осуществляется возврат освободившегося буфера
Вызывающий
модуль ожидает поступления сообщения
Вызывающий
модуль ожидает поступления сообщения
DIALOGUE
DIALOGUE
Активный управляющий пакет обмена сообщениями М
Рис. 6.9. Модифицированная структура интерфейса DIALOGUE/COMM.
буфера и ожидание окончания его заполнения поступившим со< общением — путем вызова E.RCVE, а последующая передача сообщения — путем вызова входа E.PUT.
Модифицированный модуль дешифратора событий в диалоговой системе. Рис. 6.10 в целом иллюстрирует усовершенствованную схему работы задачи Е, причем на рис. 6.10, а изображен модифицированный конечный автомат, управляющий ее функционированием, а на рис. 6.10,6 представлена соответствующая программа на языке Ада. Новые возможности этого автомата получены путем добавления двух дополнительных состояний: READY_TO_SEND (ГОТОВНОСТЬ-К-ПЕРЕСЫЛ- КЕ) и SENDING (ПЕРЕСЫЛКА),), а также двух вспомогательных переменных: IN-MSG (ВХОДЯЩЕЕ-СООБЩЕНИЕ) и RX_DONE (БУФЕР_РХ_СВОБОДЕН). Состояние READY-,
ТО-SEND обеспечивает выполнение условий защиты оператора приема, принадлежащего входу GET (который открыт только в этом состоянии). В состоянии SENDING активизируются средства, которые позволяют заблокировать поток символов от оператора в буфер ТХ до момента, когда последний освободится. До того как это произойдет, невозможен переход в состояние IDLE, являющееся единственным состоянием конечного автомата, в котором действия оператора не зависят от состояния буферов ТХ. Переменная IN-MSG используется для того, чтобы регистрировать факт наличия сообщения после вызова входа PUT; эти вызовы могут быть приняты в любом состоянии конечного автомата, но смена состояний реализуется только в одном из них (IDLE). Иными словами, роль переменной INMSG заключается в регистрации факта обращения к входу PUT, с тем чтобы при наступлении других событий могли быть
Прием вызова PUT НажатиеПрием вызова PUT Нажатиелюбой клавишилюбой клавишиSENDINGSENDINGПересылкаПересылкаРезервированиеРезервированиеОсвобождениеОсвобождениеРезервированиеРезервированиеРезервирование при разрешенном символеРезервирование при разрешенном символеПрием ■ вызова PUTПрием ■ вызова PUTНажатие любой клавишиНажатие любой клавишиПрием вызова RETURNПрием вызова RETURNIN _ MSG= FALSEIN _ MSG= FALSEПрием вызова PUTПрием вызова PUTIN„ MSG = TRUEIN„ MSG = TRUEОсвобождение при IN _MSG=TRUEОсвобождение при IN _MSG=TRUEREADYREADYTO SENDTO SENDBUSYBUSYREMOTEREMOTEBUSYBUSYLOCALLOCALПриемПриемвызова GETвызова GETПриемПриемвызова PUTвызова PUTОсвобождениеОсвобождениепри IN — MSG = FALSEпри IN — MSG = FALSE(a) Конечный автомат.(a) Конечный автомат.ОсвобождениеОсвобождениеПрием вызова PICKUPПрием вызова PICKUPПрием вызова RETURN при IN — MSG = TRUEПрием вызова RETURN при IN — MSG = TRUERX-DONERX-DONE= FALSE= FALSERX DONERX DONE- TRUE- TRUE
Прием вызова PUT Нажатие
Прием вызова PUT Нажатие
любой клавиши
любой клавиши
SENDING
SENDING
Пересылка
Пересылка
Резервирование
Резервирование
Освобождение
Освобождение
Резервирование
Резервирование
Резервирование при разрешенном символе
Резервирование при разрешенном символе
Прием ■ вызова PUT
Прием ■ вызова PUT
Нажатие любой клавиши
Нажатие любой клавиши
Прием вызова RETURN
Прием вызова RETURN
IN _ MSG
= FALSE
IN _ MSG
= FALSE
Прием вызова PUT
Прием вызова PUT
IN„ MSG = TRUE
IN„ MSG = TRUE
Освобождение при IN _MSG=TRUE
Освобождение при IN _MSG=TRUE
READY
READY
TO SEND
TO SEND
BUSY
BUSY
REMOTE
REMOTE
BUSY
BUSY
LOCAL
LOCAL
Прием
Прием
вызова GET
вызова GET
Прием
Прием
вызова PUT
вызова PUT
Освобождение
Освобождение
при IN — MSG = FALSE
при IN — MSG = FALSE
(a) Конечный автомат.
(a) Конечный автомат.
Освобождение
Освобождение
Прием вызова PICKUP
Прием вызова PICKUP
Прием вызова RETURN при IN — MSG = TRUE
Прием вызова RETURN при IN — MSG = TRUE
RX-DONE
RX-DONE
= FALSE
= FALSE
RX DONE
RX DONE
- TRUE
- TRUE
task EVENT_DECODER is
entry PUT_STROKE (К : in ...); --НАЖАТИЕ КЛАВИШИ (ОЖИДАНИЕ ОТСУТСТВУЕТ), entry GET(.,.);- УСЛОВНОЕ ОЖИДАНИЕ ИСХОДЯЩЕГО СООБЩЕНИЯ entry PUT(...);- ВХОДЯЩЕЕ СООБЩЕНИЕ (БЕЗ ОЖИДАНИЯ) entry RETURN;...); -• ВОЗВРАТ ОСВОБОДИВШЕГОСЯ БУФЕРА (БЕЗ ОЖИДАНИЯ) entry PICKUP!...); - УСЛОВНОЕ ОЖИДАНИЕ СВОБОДНОГО БУФЕРА СООБЩЕНИЙ end EVENT_DECODER;
task body EVENT_DECODER is
type STATE is (IDLE, BUSY_LOCAL, BUSY^REMOTE, READY^TO-SEND, SENDING);
S : STATE : = IDLE;
IN_MSG, RX_DONE : BOOLEAN : = FALSE;
begin
loop
■select
accept PUT_STROKE (K : ...);
do-. ...
if К = RELEASE and IN_MSG then IN_MSG I = FALSE; SCREEN.SWITCH; end if; case S is
when IDLE = >
if К = RESERVE then S : = BUSY_LOCAL;
else RING^BELL; end if;
When BUSY_LOCAL = > case К is when RELEASE = > if not INMSG then S : = IDLE;
SCREEN,CLEAR; elseif INMSG then S : = BUSY_REMOTR SCREEN.SWITCH;
end if;
when SEND = >
S : = READY_TO_SEND;
When in LEGAL_CHAR = > SCREEN.WRITE (K|;
when OTHERS = > RING_BELL;
end case;
when BUSY_REMOTE = > if К = RELEASE then
S: = IDLE;
SCREEN.CLEAR;
RX_DONE : = TRUE; else RING_BELL; end if; end case;
end;
(6) Скелет Ада-программы.
рг
accept PUTiM ;...);
do'
IN_MSG : = TRUE;
if S = IDLE or S = SENDING thenSCREEN.SWITCH; end if;
if S = IDLE then S ; = BUSY. REMOTE; end if; end;~
■W
when RXDONE = >
accept PICKUP (..,);
do
GIVE_EMPTY_BUFFER;
IN_MSG : = FALSE; .
RX_DONE : = FALSE;
end;
or
When S = SENDING = >
accept RETURN (M :.,.);
do
if not IN_MSG then S ;' = IDLE;
elseif INMSG then
S ; = BUSY_REMOTE;
end if;
end;
end select;
end loop;
end EVENT_DECODER;
(6) Скелет Ада-прОграммы (продолжение).
Рис. 6.10. Схема функционирования модифицированного модуля дешифратора событий. (Примечание. 1. События, инициируемые оператором путем нажатия клавиш, подчеркнуты. 2. Логическая переменная IN—MSG указывает, можно ли вывести на экран дисплея сообщение из буфера RX, или оно уже было выведено. 3. Нажатие клавиши RELEASE вызывает возврат свободного буфера (если он есть) модулю М независимо от состояния, в котором он находится.)
произведены соответствующие изменения состояний. Вызовы входа PUT допускаются в любом состоянии, поскольку разрешение модулю М на прием информации выдается задачей Е путем предоставления свободного буфера; поэтому отсутствует необходимость в регулировании потока данных, поступающих в буфер RX, посредством установки «предохранителя» (guard) на входе PUT, как это было сделано выше при проектировании диалоговой системы в ее исходном варианте. Переменная RX-DONE используется в качестве предохранителя на входе PICKUP: в любом состоянии системы при нажатии клавиши RELEASE переменная RX-DONE принимает значение TRUE ЦИСТИНА) при условии, что IN-MSG принимает такое же
Условные обозначения:
О™*»- заполненный буфер
Рис. 6.11. Структура пассивного управляющего пакета обмена сообщениями (при отсутствии протокола обмена и наличии буферов ТХ и RX, предназначенных для передачи и приема одного сообщения соответственно).
значение, и в результате защищенный вход PICKUP открывается. Как только будет выполнен оператор приема, обе переменные примут значение FALSE (ЛОЖЬ).
Управляющий пакет обмена сообщениями. Поскольку пакет М не является активным, все его функции, как показано на рис. 6.11, могут быть реализованы интерфейсными процедурами M.SEND и M.RCVE. Задачи ЕТХ и ERX при вызове этих процедур попадают в состояние ожидания разрешения на обмен данными и/или получения кадровых буферов.
Процедура M.SEND вначале ожидает по входу F.SEND разрешения на использование буфера ТХ. Затем при его освобождении она вызывает вход B.RICKUP для получения свободного буферного блока, копирует туда фрагмент сообщения и, наконец, обращается к входу F.SEND для передачи. Возврат после выполнения оператора приема F.SEND, как правило,
является разрешением на передачу следующего кадра. Выполнение операторов тела цикла, содержащего вызовы входов В. PICKUP и F.SEND, повторяется до тех пор, пока сообщение не будет полностью передано. При последнем обращении к входу F.SEND один из параметров вызова, задаваемый процедурой M.SEND, указывает, что ожидание разрешения на передачу очередного кадра нежелательно. При последнем обращении к входу F.SEND процедура M.SEND возвращает теперь уже пустой буфер вызывающему модулю. Отметим, что явной передачи параметров из пакета F в пакет М для получения разрешения на доступ к буферу ТХ не требуется, поскольку пакет М в нашем примере не имеет возможности осуществлять пересылку нескольких кадров данных за одно обращение к входу F.SEND. Возврат после выполнения оператора приема F.SEND служит неявным разрешением на передачу одного кадра (при условии, однако, что значение соответствующего параметра указывает на допустимость ожидания).
Процедура M.RCVE вначале по входу F.RCVE ожидает поступления кадра данных, затем после приема она копирует его в свободный буфер и через вход В.RETURN возвращает освободившийся буферный блок в пул. По завершении приема сообщения (его конец обнаруживается путем проверки информационной части кадра) процедура M.RCVE возвращает буфер, теперь уже заполненный информацией сообщения, инициатору вызова. В этот момент поступление кадров данных в буфер RX прекращается, поскольку обращения к входу F.RCVE больше не произойдет до тех пор, пока не будет вызвана процедура M.RCVE.
Управляющий пакет логического обмена кадрами данных. На рис. 6.12 представлена схема функционирования активного пакета F, осуществляющего управление логическим обменом кадрами данных. Основными новыми особенностями внешнего пакета Е, отличающими его от пакета М, являются использование пакета внешнего таймера и наличие процедуры START. Активизация этой процедуры любым модулем более высокого уровня на указанном рисунке не отмечена, поскольку при проектировании мы не определили,каким образом подсистема СОММ взаимодействует с локальными управляющими модулями системы, которые выполняют ее начальный запуск. Основной новой внутренней особенностью этого пакета по сравнению с пакетом М является наличие задачи FS, которая осуществляет ряд сервисных функций при обмене кадрами данных. Задачи FTX и FRX функционируют в тесном взаимодействии с задачей FS. Пакет F реализует протокол дуплексного обмена последовательностями кадров данных, поступающих автономно от модулей верхнего и нижнего уровней. Указанные последователь-
Условные обозначения
О*—» заполненный буфер
разрешение на передачу данных
О >■ свободный буфер (или какой-либо специальный параметр)
Рис. 6.12. Управляющий пакет логического обмена кадрами данных. (Примечание. 1. Вход закрыт, если в фазе передачи данных не предоставлен буфер ТХ. 2. Вход закрыт, когда в фазе передачи данных нет кадров данных для приема. 3. Вход закрыт, когда нет информационных кадров, подлежащих передаче.)
ности не являются независимыми из-за необходимости подтверждений приема информации и поэтому под управлением пакета возможно добавление кадров данных в поток или исключение их оттуда. Всю эту работу выполняет задача FS, а
Q Зак. 455
задачи FTX и FRX реализуют функции транспортировки кадров взаимодействия с пакетом Р, который осуществляет управление физическим обменом, и тем самым освобождает от этих «обязанностей» задачу FS.
У задачи FS имеются входы, вызываемые «сверху» вышестоящими модулями: вход SEND для передачи, и вход RCVE для приема кадров, содержащих фрагменты сообщения. Входы GET (ПОЛУЧИТЬ) и PUT (ПОМЕСТИТЬ) служат для аналогичной цели, но вызываются только «снизу» модулями нижестоящего уровня. Кроме того, имеются вход START, при обращении к которому запускается стартовый протокол обмена данными, и вход PICKUP, вызов которого предшествующим (в иерархической структуре) модулем, как будет показано ниже, обеспечивает ему разрешение на информационный обмен в форме предоставления свободного буфера ТХ. При этом оператор задержки определяет интервал времени, в течение которого должно ожидаться подтверждение приема информации.
При каждом обращении к входу SEND задачи FS инициатору вызова возвращается в качестве выходного параметра разрешение на пересылку данных; если значение этого параметра равно нулю и вызывающий модуль «согласен» на ожидание, то процедура SEND вызывает вход PICKUP для получения свободного буфера.
В теле задачи FTX реализуется цикл, на каждой итерации которого посредством обращения к процедуре P.SEND и последующего вызова входа FS.GET осуществляется передача одного кадра данных. Возврат из процедуры P.SEND означает разрешение на передачу следующего кадра. Отметим, что такой механизм получения разрешения является строго локальным и работает только при взаимодействии пакетов F и Р; при его использовании нет возможности различать информационные и управляющие кадры. При начальном запуске разрешение считается выданным и в этом случае задача FTX обращается сначала к входу FS.GET, чтобы дождаться поступления кадра данных.
Тело задачи FRX в свою очередь тоже представляет собой цикл, на каждой итерации которого путем обращения к процедуре P.RCVE и последующего вызова входа FS.PUT осуществляется передача одного кадра данных. При начальном запуске задача FRX обращается прежде всего к процедуре P.RCVE и ожидает поступления кадра данных. На задачу FS возложена функция блокирования приема новых кадров в случае, когда окно буфера РХ заполнено.
Какой же должна быть внутренняя логика задачи FS, осуществляющей все эти функции? С точки зрения модульности желательно разделить логику, реализуемую протоколом равно-
Условные обозначения:
О—►- буферы для кадров, EQ - постановка в очередь, xpR - пересылка между очередями* DQ - исключение из очереди; Q идентификаторы очереди; С г- код операции.
Рис. 6.13. Внутренние пакеты задачи FS.
правного информационного обмена, и локальную системозависимую логику регулирования потока данных, манипулирования кадрами и организации очередей. Рис. 6.13 служит иллюстрацией возможного подхода, удовлетворяющего этим требованиям. Пакет F-PROTOCOL полностью реализует логику протокола равноправного обмена, включая начальный запуск и передачу данных. Различные операторы приема задачи FS интерпретируют вызовы соответствующих им входов и пересылаемые параметры как события, происходящие в рамках протокола обмена. Идентификаторы событий пересылаются процедуре PROCESS пакета F-PROTOCOL в качестве входных параметров; ее выходными параметрами будут коды операций, используемые при последующих действиях. Тот оператор приема, который при появлении соответствующего события первым вызвал эту процедуру, обрабатывает полученные коды и выполняет предписываемые ими действия. Эти операции предусматривают подготовку и постановку информационных и управляющих кадров в очередь для передачи, а также соответствующее упорядочение их при приеме. Выполнение этих операций реализуется с помощью пакетов F-QUEUE и F-MANIPULATE.
При достаточно аккуратном использовании принципа организации пакетов логику задач, подобных FS, можно структури-
ровать так, что их внутренний пакет, реализующий протокол равноправного обмена, будет мобильным и пригодным для реализации в самых различных вариантах диалоговых систем. Например, пакет, обеспечивающий дисциплину, при которой вызывающие модули ожидают поступления элементов данных (как в нашем случае), может применяться в системе, где нет такого требования, и при возврате из соответствующей процедуры просто пересылаются значения параметров, указывающих на отсутствие информации для приема, а пакет, спроектированный для системы, в которой используются задачи-курьеры (как в нашем проекте), мог бы успешно работать в системе, основанной на концепции буферизующих задач (см. рис. 6.4,в).
Основной задачей пакета F-PROTOCOL является управление конечными автоматами и формирование значений вспомогательных переменных, позволяющих контролировать работу системы в фазах начального пуска и передачи данных. В случае нашего простого протокола обмена имеются только один конечный автомат и две вспомогательные переменные. Конечный автомат реализует передачу последовательностей управляющих блоков между равноправными модулями взаимодействующих систем, в результате которой подтверждается установление связи между ними и готовность линии к передаче кадров данных. Вспомогательные переменные представляют собой текущие исходящие и входящие номера, присваиваемые пересылаемым кадрам данных.
На рис. 6.14, а приведена схема, иллюстрирующая работу простого конечного автомата. Эта схема основана на не совсем реалистичных предположениях, которые приняты исключительно с целью более понятного изложения.
Системы могут запускаться независимо друг от друга в любое время, но если запуск осуществлен, то они уже не выключаются. Поэтому поступление в систему, находящуюся в состоянии UP (ВКЛЮЧЕНО), управляющих кадров START не означает попытку рестарта после аварийной ситуации, возникшей в фазе передачи данных, а имеет место только в процессе активизации линии связи, когда истекает время задержки, предусмотренное в состоянии COMING_UP (УСТАНОВЛЕНИЕ-СВЯЗИ).
В состоянии UP единственной требуемой операцией является формирование текущих исходящих и входящих - номеров пересылаемых кадров. При самом первом переходе системы в это состояние соответствующим переменным присваиваются нулевые значения; согласно предположению 1, при поступлении в систему, находящуюся в состоянии UP, управляющих кадров START повторное занесение нуля в эти переменные не требуется,
Состояние UP является единственным состоянием системы, при котором осуществляется информационный обмен.
Чтобы ощутить преимущества такого подхода, достаточно познакомиться со спецификацией пакета F-PROTOCOL, приведенной на рис. 6.14,6. В ней определены допустимые события и соответствующие им действия, но нет никаких операций обработки управляющих и информационных кадров. Параметрами событий и действий являются записи возможных вариантов, которые позволяют формировать и воспринимать элементы соответствующих последовательностей событий и действий, происходящих в системе.
Исходящие и входящие номера, содержащиеся в принимаемых информационных кадрах, пересылаются в тело пакета, где в результате внутренних операций исходящий номер увеличивается на единицу и запоминается с целью использования в качестве входящего номера очередного кадра данных; принятый же входящий номер определяет номера отправленных ранее кадров, по которым имеется подтверждение приема.
При поступлении такого подтверждения или при его отсутствии в течение установленного интервала времени пара исходящих номеров извлекается из памяти пакета и по ней идентифицируется диапазон номеров отправленных информационных кадров, которые следует либо возвратить в пул свободных буферов, либо передать повторно.
Исходящий номер кадра формируется в рамках пакета тогда, когда вышестоящим модулем предоставляется свободный буфер для передачи; этот номер заносится в выделенный буфер в качестве исходящего номера текущего информационного кадра.
Входящий номер кадра формируется в рамках пакета в тот момент, когда свободный буфер подготовлен для пересылки на нижний уровень и последующего использования его там для передачи сообщения; этот номер заносится в выделенный буфер в качестве входящего номера текущего информационного кадра.
Тело пакета F-PROTOCOL совсем не трудно реализовать при помощи таблиц состояний конечного автомата, следуя методу, использованному в гл. 4 для проектирования модуля дешифратора команд системы LIFE. Детальную разработку этого пакета оставляем читателю в качестве упражнения.
При наличии рассмотренного выше представления пакета F-PROTOCOL нетрудно оценить возможность его использования на различных входах задачи FS для управления потоком информационных кадров.
На рис. 6.15 отображен характер внутреннего потока данных задачи FS. Предполагается, что доступ к внутренним
очередям реализуется пакетом F-QUEUE, а манипулирование информационными кадрами — пакетом F_MANIPULATE; оба пакета схематически изображены на рис. 6.13. Примерами операций манипулирования кадрами служат добавление заголовков при передаче и удаление их при приеме, формирование управляющих кадров, а также занесение в заголовки пересылаемых кадров соответствующих порядковых номеров.
Очередь информационных кадров, подлежащих повторной передаче, содержит копии уже отправленных блоков, ожидающих подтверждения приема. Максимальная длина этой очереди определяется величиной окна, используемого для регулирования потока информации при передаче. Копии кадров удаляются из этой очереди только в том случае, если поступает уведомление об их приеме; соответствующие буферы при этом возвращаются в пул. По истечении определенного интервала времени копии неквитированных кадров переводятся из указанной очереди в очередь на передачу. Допустимое время задержки будет корректироваться при каждом обращении к пакету
PLEASE START/TX STARTPLEASE START/TX STARTRX START/TX START_ACK и INITRX START/TX START_ACK и INIT. RX START/TX START_ACK и INIT. RX START/TX START_ACK и INITDOWNDOWNCOMING UPCOMING UPRX START_ACKRX START_ACK(a) Схема конечного автомата.(a) Схема конечного автомата.RX START/TX START_ACKRX START/TX START_ACKTIMEOUT/TX STARTTIMEOUT/TX STARTОбе взаимодействующие системы находятся в состоянииUP_STATEОбе взаимодействующие системы находятся в состоянииUP_STATEСвязь с абонентом не установленаСвязь с абонентом не установленаRXSTART_ACK/ INITRXSTART_ACK/ INITУсловное обозначение: событие/ действиеУсловное обозначение: событие/ действие
PLEASE START/TX START
PLEASE START/TX START
RX START/TX START_ACK и INIT
RX START/TX START_ACK и INIT
. RX START/TX START_ACK и INIT
. RX START/TX START_ACK и INIT
DOWN
DOWN
COMING UP
COMING UP
RX START_ACK
RX START_ACK
(a) Схема конечного автомата.
(a) Схема конечного автомата.
RX START/TX START_ACK
RX START/TX START_ACK
TIMEOUT/TX START
TIMEOUT/TX START
Обе взаимодействующие системы находятся в состоянии
UP_STATE
Обе взаимодействующие системы находятся в состоянии
UP_STATE
Связь с абонентом не установлена
Связь с абонентом не установлена
RXSTART_ACK/ INIT
RXSTART_ACK/ INIT
Условное обозначение: событие/ действие
Условное обозначение: событие/ действие
package FPROTOCOL is' type.EVENT_TYPE is (PLEASE_START,TIMEOUT,RX_STAR\,RX_START_ACK,RX_DATA,REQUEST_TX_DATA.TX_DATA);
type STATUS-TYPE is (OK, NOT_OK);
type WINDOW is range 0 .. MAX; type EVENT (INDICATOR:EVENT_TYPE) is record case INDICATOR is when RXDATA = >
SEND_COUNT, RCVE_COUNTWINDOW;^ when others = >; end case; end record;
type ACTJON_TYPE is (TX_START, TX_START_ACK, ■q_request_tx„data,
tx_data' CLEAR_ACKED_FRAMES, SEND_UNACKED_FRAMES, DISCARD_RX_DATA, NIL);
type ACTION(INDICATOR;ACTION_JYPE) is record1
TIMEOUT_PERIOD;TIME; case INDICATOR is
. when Q_REQUEST_TX_DATA = >SEND_COUNT, TX_CREDIT:WINDOW;When TX_DATA = >RCVE_COUNT: WINDOW;
when CLEAR_ACKED_FRAMES = > FIRST_FRAME, LAST_FRAME, TX_CREDIT:WINDOW;, When SEND_UNACKED_FRAMES = >
FIRST_FRAME, LAST_FRAME:WINDOW; when others = >;
end case; end record; procedure PROCESS (E;in EVENT; A:out ACTION); end F_PROTOCOL;’
16) Спецификация управляющего пакета обмена на языке Ада/
Рис. 6.14. Логическая схема функционирования пакета F-PROTOCOL.
О--» управляющие кадры
Рис. 6.15. Детализированная внутренняя логика работы задачи FS; поток кадров данных.
F-PROTOCOL, что гарантирует выполнение соответствующей операции не позднее момента, определяемого суммой двух величин: времени передачи самого последнего кадра из «повторной» очереди и временного интервала, отведенного для подтверждения приема.
В очереди кадров, подлежащих передаче, находятся как информационные, так и управляющие блоки, дальнейшая работа с которыми осуществляется оператором приема GET по принципу «первым пришел — первым обслужен».
В очереди на прием «стоят» кадры данных, воспринятые модулем, но еще не обслуженные оператором приема RCVE. Максимальная длина этой очереди определяется величиной окна, используемого для регулирования потока информации при приеме. При отсутствии свободных мест в этой очереди, согласно требованиям со стороны пакета F-PROTOCOL, оператор приема PUT должен отвергать очередные кадры входящего потока.
Читателю предлагается самостоятельно провести дальнейшую разработку деталей взаимодействия между различными входами и внутренними пакетами задачи FS, осуществляющей управление информационным потоком, который схематически изображен на рис. 6.15.
Рис. 6.16. Структура управляющего пакета физического обмена кадрами данных."
Управляющий пакет физического обмена информационными кадрами. В пакете Р, осуществляющем управление физическим обменом, имеются только две задачи: РТХ и PRX (рис. 6.16). Эти задачи представляют собой стандартные программы обслуживания прерываний, взаимодействующие с оборудованием посимвольной передачи данных, о котором упоминалось в начале данной главы. Аппаратные средства связи, от которых исходят сигналы прерываний, осуществляют передачу отдельных символов. На стороне системы через вход SEND задачи РТХ пересылаются «сверху — вниз» кадры данных, а «снизу — вверх» — буфер ТХ, служащий разрешением на передачу информации: на входе PICKUP (ВОССТАНОВЛЕНИЕ) задачи РТХ реализуется ожидание нового «кредита» на передачу, если он исчерпан процедурой SEND; через вход RCVE задачи PRX пересылаются «снизу — вверх» информационные кадры, а «сверху — вниз» — свободные буферы. .
Использование процедуры P.RCVE для нисходящей передачи свободных буферов избавляет задачу PRX от необходимости
непосредственного обращения к буферному пулу, что уменьшает вероятность пропуска ею некоторых символов. Благодаря такому решению задача PRX активизируется лишь при наличии соответствующего числа свободных буферов из пула (хотя бы Двух).
При нормальном функционировании процедура P.RCVE вызывает вход NO-WAIT-PICKUP задачи В в том случае, когда значение переменной TALLY (ЯРЛЫК) больше нуля. Эта переменная используется для хранения текущей разности между числом кадров, отправленных снизу — вверх, и числом свободных буферов, переданных сверху — вниз. Как будет показано ниже, вызов входа PICKUP задачи В осуществляется только тогда, когда от задачи PRX поступает сообщение, что она исчерпала свой запас свободных буферов.
Задача, управляющая пулом свободных буферов, должна иметь дополнительный вход NO-WAIT-PICKUP (ВОССТА- НОВЛЕНИЕ-БЕЗ-ОЖИДАНИЯ), чтобы модуль, вызывающий процедуру P.RCVE, не сталкивался с конфликтной ситуацией, при которой он должен «стоять» сразу в двух очередях: на входе задачи В в ожидании свободных буферов, и на входе задачи PRX в ожидании заполненных буферов. Добавление нового входа исключает всякую возможность возникновения подобного тупика.
После того как задачей PRX осуществлен прием полного кадра, предохранитель на ее входе RCVE устанавливается в состояние TRUE (если он был в состоянии FALSE) и задача вновь оказывается готовой к заполнению очередного свободного буфера. В результате приема вызова входа RCVE полученный кадр данных передается вызывающему модулю, а предохранитель входа RCVE опять устанавливается в состояние FALSE при условии, что задача PRX располагает хотя бы одним свободным буфером, а кадров, подлежащих обработке, больше нет. Если же это условие нарушается, т. е. у задачи нет ни кадров, ни свободных буферов, то она уведомляет об этом модуль, обратившийся к выходу RCVE, возвращая ему соответствующее значение параметра состояния системы. До тех пор пока у задачи PRX имеется по крайней мере один свободный буфер, а принятые информационные кадры отсутствуют, вход RCVE остается закрытым.
Для формирования внутренней очереди из копий передаваемых кадров (представленных, возможно, ссылочными переменными) в задаче РТХ имеется специальная область памяти, рассчитанная на хранение определенного числа элементов (как минимум двух). После передачи копии некоторого кадра задача немедленно освобождает занимаемое им место в памяти (уничтожая таким образом копию) и начинает обработку копии еле-
дующего кадра из очереди. До тех пор пока свободные места в очереди отсутствуют, вход PICKUP остается закрытым с помощью защитной блокировки.
Средства, инициирующие сигналы прерываний, осуществляют посимвольную передачу информационных кадров между программой и аппаратурой, добавляя символы в буфер или извлекая их из него. Такой способ передачи является следствием сделанного в начале данной главы предположения, что аппаратные средства системы ориентированы на посимвольную обработку; в результате производительность системы может оказаться крайне низкой. Кроме того, ввиду замедления работы системы, вызванного непроизводительными затратами времени на организацию рандеву, при выполнении быстрых операций обмена в синхронном режиме может происходить потеря символов. Подход, позволяющий избавиться от указанных выше проблем, состоит в том, чтобы писать стандартные программы обработки прерываний на языке ассемблера и, используя механизм фиксированных временных задержек, возлагать на задачу PRX, например, периодическую проверку наличия символов и извлечение их из входного буфера программы обслуживания прерываний. Альтернативный способ действий — изменение технических требований в сторону улучшения рабочих характеристик аппаратных средств.
Заключительные замечания к проекту
При обсуждении нашего проекта мы опустили многие подробности, связанные с системными аспектами. Не рассматривались, например, реальные механизмы выделения памяти под пул буферов и формирования их указателей. Практически не исследовались вопросы организации внутренних очередей в различных модулях, в которых могут накапливаться данные, спецификации пакетов и задач не содержали излишних подробностей и были опущены детали объявления типов параметров.
Логика работы системы разрабатывалась большей частью с использованием рисунков и путем словесных пояснений. Для иллюстрации некоторых новых ключевых положений мы привлекали лишь небольшие фрагменты программ. В частности, были приведены текст программы для задачи дешифратора событий, а также упрощенный вариант спецификации пакета F-PROTOCOL. В то же время мы не дали описания управляющих пакетов обмена сообщениями и физического обмена кадрами данных, поскольку читатель не получил бы здесь никакой новой информации.
Пакет F-PROTOCOL можно было бы, конечно, сделать более универсальным, усложнив в деталях его внутреннюю
структуру (соответственно уровню сложности нового варианта), однако характер его интерфейсов с локальной системой при передаче и приеме данных, а также при управлении потоком кадров остался бы точно таким, как и в вышеописанном проекте подсистемы СОММ, независимо от уровня внутренней сложности. Так, например, появление новых типов информационных кадров в протоколе обмена потребует, конечно, введения дополнительных компонентов в вариантные записи, характеризующие возможные события и действия.
Подсистему СОММ в том виде, в котором она спроектирована, можно рассматривать как некоторый логический уровень эскизного описания архитектуры системы. Данный материал целесообразно использовать в качестве некоторого стержня реального проекта. Основываясь на изложенных идеях, следует разработать детализированные спецификации интерфейсов всех пакетов и задач, начав с определения опущенных нами деталей.
В оставшихся разделах главы мы проанализируем проект подсистемы СОММ с двух точек зрения: в разд. 6.6.1 будут рассмотрены некоторые обобщения, ведущие к расширению функциональных возможностей, а в разд. 6.6.2 мы оценим возможности других проектных решений, ведущих к построению систем иной струкуры.
Обобщение результатов проектирования
Проектные решения по системе в целом весьма слабо зависят от деталей протокола обмена кадрами данных. Поэтому можно сравнительно легко включить в наш проект некоторые функциональные возможности этого протокола, такие, как явное управление сквозной передачей потока сообщений, управление выключением и рестартом средств связи и передача уведомлений об отказах линии передачи данных. Эти изменения могут повлиять главным образом на пакет протокола обмена.
Включение в этот пакет механизма сквозного управления потоком информационных кадров не должно влиять на механизмы локального регулирования потока информации, уже реализованные в управляющем пакете логического обмена.
Способ регистрации отказов линии связи, иллюстрируемый рис. 6.17, состоит в том, что вводится специальная задача CHECKER (КОНТРОЛЕР), которая ожидает поступления на вход задачи, реализующей обмен кадрами данных, особого сигнала, формируемого при отказе линии передачи. После этого задача-контролер должна отправить уведомления от отказе всем другим пакетам и задачам, к которым это событие имеет непосредственное отношение. Конечно, для обеспечения такой структуры взаимодействий упомянутые программные модули
Iдля регистрации любых I
1существенных событий I
1в канале связи1
Рис. 6.17. Схема оповещения модулей верхних уровней системы о событиях, происходящих на уровне управления обменом кадрами данных. (Примечание. На рисунке изображены не все процедуры и входы задач.)
должны быть снабжены необходимыми процедурами и входами, а их внутренняя логика соответствующим образом модифицирована.
Для осуществления приема и передачи сообщений с использованием нескольких буферов (более двух) потребуется создание активного пакета управления обменом. Необходимо будет также реализовать протокол управления потоком сообщений, который обеспечивал бы автоматическое восстановление информации при выключении аппаратуры связи или удаленного терминала и рестарт системы без потери или дублирования сообщений. Возможная структура такой системы с внешними интерфейсами, как у системы, описанной ранее, изображена на рис. 6.18. Ее логика аналогична логике работы пакета F с той только разницей, что разрешения на обмен информацией выдаются в форме предоставления текущих буферов, которые после их использования должны возвращаться «владельцу».
Условные обозначения; €>■»* заполненные буферы О—►- свободные буферыУсловные обозначения; €>■»* заполненные буферы О—►- свободные буферыУправляющий пакет обмена сообщениями МУправляющий пакет обмена сообщениями МУправляющий пакет логического обмена кадрами данных FУправляющий пакет логического обмена кадрами данных FЗадача В, управляющаяЗадача В, управляющаядоступом в буферный пулдоступом в буферный пулРис. 6.18. Возможная структура активного управляющего пакета обмена сообщениями. (Примечание. 1. Вход RCVE закрыт до тех пор, пока нет сообщений для приема. 2. Вход PICKUP закрыт до тех пор, пока не закончится передача сообщения. 3. Вход GET закрыт до тех пор, пока отсутствует информация, подлежащая передаче. 4. Вход WAIT закрыт, если нет свободного буфера сообщений RX.)Рис. 6.18. Возможная структура активного управляющего пакета обмена сообщениями. (Примечание. 1. Вход RCVE закрыт до тех пор, пока нет сообщений для приема. 2. Вход PICKUP закрыт до тех пор, пока не закончится передача сообщения. 3. Вход GET закрыт до тех пор, пока отсутствует информация, подлежащая передаче. 4. Вход WAIT закрыт, если нет свободного буфера сообщений RX.)
Условные обозначения; €>■»* заполненные буферы О—►- свободные буферы
Условные обозначения; €>■»* заполненные буферы О—►- свободные буферы
Управляющий пакет обмена сообщениями М
Управляющий пакет обмена сообщениями М
Управляющий пакет логического обмена кадрами данных F
Управляющий пакет логического обмена кадрами данных F
Задача В, управляющая
Задача В, управляющая
доступом в буферный пул
доступом в буферный пул
Рис. 6.18. Возможная структура активного управляющего пакета обмена сообщениями. (Примечание. 1. Вход RCVE закрыт до тех пор, пока нет сообщений для приема. 2. Вход PICKUP закрыт до тех пор, пока не закончится передача сообщения. 3. Вход GET закрыт до тех пор, пока отсутствует информация, подлежащая передаче. 4. Вход WAIT закрыт, если нет свободного буфера сообщений RX.)
Рис. 6.18. Возможная структура активного управляющего пакета обмена сообщениями. (Примечание. 1. Вход RCVE закрыт до тех пор, пока нет сообщений для приема. 2. Вход PICKUP закрыт до тех пор, пока не закончится передача сообщения. 3. Вход GET закрыт до тех пор, пока отсутствует информация, подлежащая передаче. 4. Вход WAIT закрыт, если нет свободного буфера сообщений RX.)
Альтернативные проектные решения по основным компонентам системы
Подсистема СОММ была спроектирована нами с ориентацией на совместно используемые буферные пулы. Существуют по крайней мере две причины, по которым такая реализация может оказаться нежелательной:
Сложность, возникающая из-за свободного состязания модулей за обладание общими буферами и возможного размножения указателей буферов, может запутать логическую структуру взаимодействий и как следствие увели-.
чить вероятность возникновения ошибок при проектировании или реализации системы.
Прозрачность модулей, требуемая для организации совместного использования памяти, делает невозможным распределение модулей по различным процессорам, у которых может не быть общего пространства памяти.
Отметим, что при реализации верхних уровней системы принцип конкурентного доступа к общим буферам нами не применялся. Так, например, управление пулом буферов сообщений осуществлялось исключительно лишь дешифратором событий. Но что можно сказать по поводу применения аналогичного подхода к буферизации кадров? Управление буферными блоками должно быть доступно только пакету, реализующему логический обмен. В этом случае должно осуществляться не раздельное получение свободных буферов взаимодействующими модулями, а их обмен на заполненные буферы при каждом акте соответствующего взаимодействия. При этом в случае передачи пустые буферы, движущиеся сверху вниз, должны обмениваться на заполненные, а в случае приема, наоборот, заполненные буферы должны обмениваться на пустые.
Несмотря на то что этот подход исключает непосредственное состязание за обладание буферами, он все еще требует наличия общего буферного пула, причем замена пустых буферов на заполненные и, наоборот, заполненных на пустые, реально означает, что буферы из совместно используемого пула передаются при обращении по ссылке. Таким образом, проблема множественности ссылок не исчезает и здесь, а прозрачность оказывается нереализованной.
Если к проекту предъявляется требование обеспечения прозрачности системы по отношению к возможному отсутствию общей памяти модулей, то обмен данными при межмодульных взаимодействиях должен осуществляться в результате вызова по значению, как показано на рис. 6.19. Каждый из модулей должен при этом иметь специальную область для размещения буферов, копируемых из одного модуля в другой. При таком подходе, когда осуществляется реальное копирование информации, не имеет смысла говорить о получении разрешения на обмен в форме предоставления свободных буферов; в данном случае оно должно выдаваться путем указания числа блоков данных в передаваемом сообщении.
В процессе проектирования подсистема СОММ приобрела вид трехуровневой системы, реализуемой шестью задачами (рис. 6.8). Использование в ней активного пакета М должно привести к увеличению этого числа до девяти. Сравнительно большое количество задач явилось результатом конкретного проектного решения, заключающегося в том, что каждый
q ЗаполненныеУ буферы I сообщенийq ЗаполненныеУ буферы I сообщенийБуфер для сообщения ТХ (разрешение на передачу) ।Буфер для сообщения ТХ (разрешение на передачу) ।(5) Прием(5) ПриемРис. 6.19. Поток кадров данных в подсистеме обмена при отсутствии совместно используемой памяти.Рис. 6.19. Поток кадров данных в подсистеме обмена при отсутствии совместно используемой памяти.(а) Передача(а) Передача
q Заполненные
У буферы I сообщений
q Заполненные
У буферы I сообщений
Буфер для сообщения ТХ (разрешение на передачу) ।
Буфер для сообщения ТХ (разрешение на передачу) ।
(5) Прием
(5) Прием
Рис. 6.19. Поток кадров данных в подсистеме обмена при отсутствии совместно используемой памяти.
Рис. 6.19. Поток кадров данных в подсистеме обмена при отсутствии совместно используемой памяти.
(а) Передача
(а) Передача
активный пакет, реализующий некоторый уровень системы, обязывает вызывающие модули ожидать при передаче данных получения разрешения на обмен и поступления информации. Таким образом, на каждом уровне системы существуют точки, в которых реализуется ожидание:
вызовов от модуля верхнего уровня;
разрешения от модуля нижнего уровня на передачу информации;
поступления информационных объектов от модуля нижнего уровня.
Вообще для обеспечения такой организации ожидания необходимо иметь в системе три задачи. Исключениями являются модуль М, который не активен, и модуль Р, для реализации ко-
торого требуются лишь две задачи обслуживания прерываний — одна для передачи и одна — для приема.
Число задач может быть уменьшено при условии, что в каждом пакете предусмотрены только вызовы без ожидания, результатом которых являются параметры состояния системы. При таком подходе необходимость в задачах-курьерах исчезает, однако в результате еще более усложняется внутренняя логика оставшихся задач.
Нетрудно установить логическую сущность возможного компромисса междупроектными решениями с большим и малым числом задач. В первом случае логика функционирования всей системы и отдельных ее задач может оказаться проще по меньшей мере по двум причинам:
отсутствует необходимость циклического слежения за наступлением определенных событий;
при совершении события задача, которая обеспечивает его обработку, получает немедленное оповещение об условиях, в которых оно произошло.
Если же число задач невелико, то «накладные расходы», связанные с их контекстным переключением и диспетчеризацией, будут меньше. Маловероятно, чтобы этот вопрос имел существенное значение для верхних уровней системы, где переключение задач наверняка происходит сравнительно редко. Однако для нижних уровней он чрезвычайно важен. Приемлемые количественные соотношения в значительной мере зависят от реализации, и их обсуждение выходит за рамки тех вопросов, которым посвящена эта книга.
Система DIALOGUE/СОММ в целом определена нами как единый узел надежности. Поэтому проектные решения по подсистеме СОММ обеспечивают защиту системы от последствий возникновения самых различных внешних неисправностей; однако средств защиты от внутренних отказов собственной логики эта подсистема не имеет. Такие отказы могут быть предотвращены путем разбиения системы на более мелкие узлы надежности, каждый из которых защищен от неисправностей, возникающих в других аналогичных узлах. В общем случае каждый модуль многоуровневой системы информационного обмена может представлять собой самостоятельный узел надежности, связанный с модулями верхнего и нижнего уровней, возможно, ненадежными каналами. В этом общем случае могут потребоваться не только протоколы горизонтального взаимодействия равноправных модулей отдельных узлов коммуникационной сети, но, вероятно, и протоколы вертикального взаимодействия различных узлов надежности, образующих разные уровни системы. Такая вероятность должна всегда приниматься во внимание, хотя в дальнейшем мы на ней останавливаться не будем.
Рис. 6.19 мог бы послужить хорошей основой для разработки системы с учетом изложенных обстоятельств.
Однако независимо от способа разбиения системы на отдельные узлы надежности существует вероятность возникновения такой ошибки во внутренней логике узла, которая приводит к разрушительным последствиям для системы, но сам узел надежности при этом полностью не выходит из строя. Такая ошибка может быть результатом, например, появления неверного бита информации в кристалле памяти. Если подобная неисправность вызывает достаточно сильное отклонение от нормы, то она может привести к тому, что поведение какого-либо блока будет казаться нормальным, но в конце концов нарушит правильную работу системы. Например, что произойдет, если в каком-либо модуле синтаксические правила, диктуемые всеми протоколами, выполняются, а семантические — нет? В этом случае модуль может подтвердить прием протокольных блоков данных, отправленных другими модулями, но не полученных, что, естественно, приведет к потере информации.
Решение подобных проблем сопряжено с серьезными трудностями, и один из возможных подходов к решению заключается в «выталкивании» симптома неисправности «на поверхность» с расчетом на то, что какой-либо модуль верхнего уровня в конце концов «заметит» возникшие неполадки и предпримет действия по восстановлению информации. Однако, применяя этот подход последовательно по всем уровням системы, мы дойдем до самого верхнего, откуда перенести решение проблемы еще выше будет уже нельзя. Тогда последним звеном в этой цепи должен стать человек-оператор системы.
Другой, более дорогостоящий подход заключается в физическом резервировании ненадежных компонентов. Например, можно выдвинуть требования, чтобы в системе было два идентичных комплекта оборудования связи и активная линия связи отключалась при чрезмерно большом потоке повторных передач сообщений.
Заключение
Важное значение в этой главе имеет не сама подсистема обмена СОММ (хотя она вполне жизнеспособна), а процесс ее проектирования, позволивший нам прийти к данной структуре, и графическая нотация, использованная для ее описания. Проектные решения представлялись в наглядной форме, удобной для группового обсуждения. Хотя сам процесс проектирования при этом носит относительно неформальный характер, рисунки трактуются формально в терминах языка Ада, и соответствующие Ада-программы могут быть написаны с их помощью почти механически.
Глава 7
Логическое проектирование многоуровневых систем: пример с применением протокола информационного обмена X. 25
Введение
В данной главе мы рассмотрим решение задачи проектирования многоуровневых систем, используя для примера многоуровневые протоколы обмена. Для большей определенности будет рассмотрен трехуровневый протокол X. 25 Международного консультативного комитета по телеграфной и телефонной связи, однако при этом подразумевается, что используемые методы применимы к многоуровневым системам различного типа. Особый интерес представляют системы, реализующие семиуровневую модель взаимодействия открытых систем, предложенную Международной организацией по стандартизации.
Из трех уровней протокола обмена Х.25 в этой главе будет рассмотрен только верхний уровень 3 (так называемый сетевой уровень). Уровень 2 этого протокола (канальный) является более сложной версией протокола управления логическим обменом кадрами данных, используемого в подсистеме СОММ (см. гл. 6). Этот протокол линий связи называется высокоуровневым протоколом управления каналом передачи данных High-Level Data Link Control (HDLC). Появившееся в нем усложнение может быть скрыто в теле пакета, реализующего канальный уровень протокола; тогда его спецификация будет полностью аналогична спецификации управляющего пакета логического обмена кадрами данных, описанного в гл. 6. Общая внутренняя структура этого пакета вполне подходит для наших целей, требуется изменить лишь некоторые детали. Однако мы не станем вдаваться в подробности проектирования такого пакета, а будем предполагать, что он уже существует.
Наша основная цель в данной главе,— используя протокол Х.25 в качестве примера, показать, как вышеописанная методология проектирования может быть применена при разработке систем с многоуровневой структурой, отражающих реальные сложные проблемы. В нашу зарачу не входят ни детальное рассмотрение протокола X.25, ни встесторонняя разработка системы, реализующей его функции. На каждом этапе проектирования будут вводиться в рассмотрение только те аспекты протокола Х.25, которые, безусловно, необходимы для принятия конкретных решений; процесс разработки будет обрываться
в тот момент, когда полученная структура оказывается ясно и однозначно объяснимой с помощью рисунков и на словах. При работе над реальным проектом, перед тем как приступить к рассмотрению деталей и написанию программ, необходимо провести анализ основных принятых проектных решений. Принимая во внимание иные цели данной главы, мы не приводим здесь примеров программ, полагаясь на то, что в предыдущих главах уже было показано, как идеи, выраженные в форме структурного графа, могут воплощаться в программы.
Для читателей, не знакомых со структурой пакета Х.25, в разд. 7.2 дается его краткое описание, достаточное для понимания материала этой главы. В разд. 7.3 разрабатывается программный пакет, реализующий сетевой уровень обмена данными с использованием протокола X. 25, разд. 7.4 содержит заключительные замечания к проекту, в разд. 7.5 рассмотрены возможные подходы к созданию более сложных многоуровневых протоколов, требуемых при организации взаимодействия открытых систем, разд. 7.6 завершает гл. 7, часть III и всю книгу.
Основные особенности протокола Х.25
Протокол Х.25 предоставляет абонентам возможность создания множества виртуальных каналов связи с удаленными системами и обмена пакетами данных по этим каналам. Виртуальный канал представляет собой логический маршрут информационного обмена, который вместе с другими виртуальными каналами может быть подсоединен к общедоступной сети передачи данных с помощью одной физической линии связи. Для каждой линии связи имеется заранее определенное множество номеров, используемых как абонентами, так и в сети для идентификации конкретных виртуальных каналов обмена, «упакованных» в данную физическую линию. Входящие и исходящие пакеты содержат номер соответствующего виртуального канала.
На практике протокол Х.25 реализуется специальным управляющим модулем, имеющимся в каждой системе. Однако при этом технические требования, вытекающие из спецификации протокола Х.25, не «навязывают» какой-либо строго определенной структуры модуля. Спецификация этого протокола имеет отношение только к движению потоков данных между различными взаимодействующими системами. Поэтому она определяет правила форматирования и упорядочения, а также функциональные возможности протокольных блоков данных (ПБД). При использовании протокола Х.25 ПБД, применяемые на сетевом уровне, называются пакетами, а на канальном — кадрами.
Рис. 7.1. Логическое представление виртуальных каналов, управляемых прото' колом Х.25.
Рис. 7.1 иллюстрирует характер применения протокола Х.25. Управляющие программы протокола передачи данных обеспечивают (модулям одного абонента) возможность создавать виртуальные каналы обмена, связывающие их с модулями другого, удаленного абонента.
Основные цели введения сетевого и канального уровней формулируются следующим образом:
. Канальный уровень обеспечивает безошибочную, упорядоченную требуемым образом передачу кадров по единственному физическому каналу (управляемую потоком информации). На этом уровне осуществляется также включение и выключение линии.
. Сетевой уровень в свою очередь обеспечивает безошибочную, упорядоченную, управляемую потоком информации передачу пакетов по каждому из виртуальных каналов, Кроме того, на этом уровне реализуются запросы на установление виртуальных каналов связи между двумя абонентами и их ликвидация. Хотя иллюстрируемые на рис. 7.1 понятия, используемые в протоколе Х.25, в основном касаются взаимодействия пользовательских модулей
посредством виртуальных каналов, многие из требований протокола связаны с организацией внутреннего интерфейса сети, т. е. обмен между абонентами не является сквозным. Однако запросы на установление и разъединение канальных соединений, а также ответы на них реализуются путем сквозных передач, и, следовательно, рассматриваемое соединение по своему характеру является сквозным. Структура системы, реализующей протокол X. 25, не зависит от того, будут ли некоторые из взаимодействий сквозными, но на функционирование верхних уровней это может оказать влияние.
Управление единственным виртуальным каналом обмена на сетевом уровне в логическом смысле очень похоже на управление единственной линией связи на канальном уровне. Виртуальные каналы обмена и линии связи являются коммуникационными соединениями, которые могут быть открыты или закрыты по желанию. Поэтому опыт, приобретенный нами в гл. 6 во время проектирования управляющего пакета логического обмена кадрами по единственной линии связи, будет использован при создании управляющих программ для каждого виртуального канала обмена на сетевом уровне. Ниже перечислены основные дополнительные возможности, предоставляемые сетевым уровнем обмена, которые нам понадобятся в дальнейшем:
наличие большого числа виртуальных каналов, которыми необходимо управлять;
динамический характер функционирования виртуальных каналов (число активных каналов изменяется во времени);
мультиплексирование активных виртуальных каналов с помощью единственного физического канала, реализующего нижний уровень информационного обмена.
Данные абонента, а также управляющая информация, используемая при обмене на сетевом уровне, передаются пакетами, длина которых обычно колеблется между 128 и 256 байт. Управляющая информация пакета, например номер используемого виртуального канала, тип пакета, номер пакета, передаваемого по данному каналу, и т. п., содержится в его заголовке. Канальная управляющая информация — исходящие и входящие номера, а также код проверочной суммы — образует заголовок и концевик кадра.
Спецификация пакета Х.25 стандартизует следующие виды информации:
типы и форматы пакетов;
возможные состояния виртуальных каналов (например, свободен, запрос на соединение, передача данных, разъединение) ;
требуемые изменения состояний при приеме пакета, по истечении некоторого заданного интервала времени и т. п.;
пакеты, необходимость передачи которых вызвана изменением состояний.
Многочисленные детали усложняют обсуждение структуры этой информации, но основные принципы ее формирования знакомы нам по предыдущим примерам, рассмотренным в гл. 4—6. Таблца 7.1. Типы и назначение абонентских пакетов, реализующих подмножество функций протокола X. 25
Название пакета
Буферный регистр
Назначение
Данные
тх
Информация абонента
Запрос на соединение
тх
Запрос на установление соединения с абонентом посредством некоторого виртуального канала (ВК)
Запрос на разъединение
тх
Запрос на разъединение конкретного вк
Прием запроса на установление соединения
тх
Ответ на запрос об установлении соединения
Подтверждение приема запроса на разъединение
тх
Ответ на запрос о разъединении
Данные
RX
Информация абонента
Входящий запрос на соединение
RX
Указывает на запрос использования некоторого ВК, поступивший от абонента
Входящий запрос на разъединение
RX
Указывает, что некоторый ВК должен быть разъединен
Установление соединения
RX
Подтверждение приема запроса на установление соединения
Разъединение
RX
Подтверждение приема запроса па разъединение
Этими соображениями вызвано использование конечных автоматов при проектировании модулей, управляющих упорядочением событий. При модульном проектировании технические подробности, связанные со спецификацией протокола Х.25, оказывают влияние только на детали схемы конечного автомата.
Для наших целей вполне достаточно будет определить типы и назначение используемых пакетов обмена. В табл. 7.1 эта информация приведена для некоторого подмножества функций протокола Х.25.
Разработка проекта многоуровневой системы с протоколом Х.25
В соответствии с общими концепциями и результатами, рассмотренными в гл. 6, было бы вполне естественным программу, реализующую протокол Х.25, разбить на уровни,
Приемзапроса
Ожида-
залроса
запроса
Передача
Прием
ФункцииуправленияФункцииуправленияПакет управления сетевым уровнемобмена с использованием протокола Х.25
Функцииуправления
Функцииуправления
ПриемПриемПередача
Прием
Прием
ФункцииуправленияФункцииуправленияуправления канальным уровнем обмена
Функцииуправления
Функцииуправления
Рис. 7.2. Характер внешних интерфейсов пакетов, реализующих протокол Х.25.
соответствующие уровням протокола, и реализовать каждый из них с помощью активного пакета, как показано на рис. 7.2. Описание параметров и условии ожидания событий, представленных на этом рисунке, будет дано в подразд. 7.3.2 в соответствии со структурой внутреннего потока данных на сетевом уровне (обмен пакетами), проектируемой ниже.
Проектирование внутреннего потока данных на сетевом уровне
Используя опыт создания систем BANK (гл. Зи 5), AGENT-POOL (гл. 5) и СОММ (гл. 6), можно сразу приступить к фазе проектирования потока данных, причем способ определения требуемой совокупности основных внутренних задач будет основываться непосредственно на результатах примеров. После этого мы рассмотрим вопросы маршрутизации межзадачных пакетов и управления потоками данных.
На рис. 7.3 схематически изображены внутренние задачи пакета, реализующего сетевой уровень обмена, и информационные потоки между ними. Многие из проектных решений, неявно отраженных на этом рисунке, знакомы нам по предыдущим примерам. В частности, необходимость использования задач, реализующих функции управления несколькими виртуальными каналами (УВК), и задачи, осуществляющей функции диспетчера, естественным образом следует из примеров подсистем BANK и AGENT-POOL. С самого начала мы увидим, что
применение структуры такого типа имеет большое практическое значение. Здесь, так же как и в примерах, рассмотренных ранее, каждой задаче пула присваивается свой постоянный номер, полностью ее идентифицирующий. В данном случае указанный номер определяет виртуальный канал, управляемый соответствующей задачей.
Задача-диспетчер, представленная на рис. 7.3, имеет несколько более широкий набор функций по сравнению с управляющими модулями, рассмотренными ранее, поскольку теперь
Рис. 7.3. Информационный поток на сетевом уровне,
запросы на организацию виртуальных каналов могут исходить не только от абонентов системы, но и от сети. Диспетчер следит за состоянием задач УВД (свободны или заняты) и выделяет их абонентам в ответ на входящие или исходящие запросы на соединение.
Каждая из задач УВК осуществляет обмен пакетами по соответствующему виртуальному каналу как при реализации функций управления (установление и разъединение канальных соединений), так и при передаче информации. Необходимость их взаимодействия с задачей-диспетчером может быть вызвана либо регистрацией поступающих вызовов, либо сообщением о том, что после разъединения задача свободна, либо получением адресов абонентов, указанных в исходящих запросах. В других случаях задачи УВК. взаимодействуют с абонентами через задачи ROUTER-IN и BUFFER-OUT. Каждой задаче УВК соответствует постоянный номер обслуживаемого ею виртуального канала, который хранится в локальной переменной и передается в случае необходимости диспетчеру или абонентам. Наличие такого номера дает им всем возможность взаимодействовать с данной задачей.
Одним из важнейших проектных решений, не отраженным непосредственно на рис. 7.3, является то, что задачи УВК могут взаимодействовать с другими задачами, пока соответствующие им каналы разъединены. Такое решение позволяет им непосредственно обрабатывать входящие пакеты, благодаря чему схема потока данных, изображенная на рис. 7.3, оказывается понятной и простой.
На рис. 7.3 показана также единственная задача, осуществляющая транспортировку информации при приеме. Эта задача имеет название ROUTER-IN (ВХОДНОИ-ТРАССИРОВ- ЩИК), поскольку в ее функции входят выбор маршрута (трассы) и доставка поступающих пакетов соответствующим задачам (УВК). Обслуживание нескольких задач УВК может осуществляться одной подобной задачей, поскольку существует единственный способ организации ожидания входящих информационных пакетов — с помощью процедуры RCVE программного пакета, реализующего канальный уровень обмена.
Доставка входящих пакетов соответствующей задаче УВК выполняется задачей ROUTER-IN. В том случае, когда задача УВК не может их принять, управление сразу возвращается задаче ROUTER-IN, которая просто отвергает эти пакеты. Регулирование информационного потока — не единственная причина того, что задача УВК не в состоянии принять входящие пакеты. Дополнительной причиной служит так называемое столкновение запросов, т. е. ситуация, когда один и тот же номер виртуального канала появляется одновременно в па-
кетах, соответствующих исходящему и входящему запросам на обмен. Для этого случая в протоколе Х.25 принято правило, согласно которому более высокий приоритет имеет исходящий запрос, а входящий игнорируется. В соответствии с этим правилом при столкновении запросов задача ROUTER_IN просто отвергает входящие пакеты.
В протоколе Х.25 термин столкновение запросов относится к пакетам, прием и передача которых осуществляются в данный момент. Попытка абонента переслать запрос на обмен данными посредством задачи УВК, которая к тому моменту уже приняла входящий запрос, не приводит в рамках этого протокола к столкновению, поскольку пакет с исходящим запросом просто не был послан, а следовательно, он и не будет принят.
Предназначенные для приема по виртуальному каналу пакеты в момент отказа от их приема могут находиться еще в модуле управления канальным уровнем обмена. При необходимости регулирования информационного потока до того, как эти пакеты будут восприняты задачей ROUTER-IN, осуществится их пересылка (наверняка неправильно) соответствующей задаче УВД. Однако, согласно требованиям протокола Х.25, пакеты будут отвергнуты в этом месте вследствие разрыва в последовательности порядковых номеров, вызванного тем, что в первый раз пакеты не были приняты.
На рис. 7.3 схематически изображена также задача ROUTE R._O ПТ (ВЫХОДНОЙ ТРАССИРОВЩИК), осуществляющая транспортировку пакетов. Для обслуживания нескольких задач УВК требуется только одна такая задача при условии, что, кроме нее (как показано на рисунке), существует еще промежуточная задача BUFFER_OUT, с помощью которой буферизуются пакеты данных, поступающие из всех задач УВК. Задача ROUTER-OUT осуществляет передачу пакетов по каналу связи после получения разрешения на обмен в форме выделенного буфера для кадров ТХ. До тех пор пока такое разрешение не получено, исходящие пакеты накапливаются задачей BUFFER-OUT; возможное количество их при этом определяется емкостью буфера. Если эта емкость равна сумме величин, каждая из которых определяется окном регулирования потока данных при передаче, осуществляемой соответствующей задачей УВК, то этим задачам не требуется получать локальное разрешение на обмен в форме буфера ТХ.
Вышеописанный механизм вполне согласуется со способом предоставления разрешения на обмен, реализованным в управляющем пакете логического обмена кадрами, который был описан в гл. 6. Однако это противоречит исходным предпосылкам, приведенным в предыдущих главах для обоснования
указанного способа. Напомним, что упомянутые предпосылки были введены для того, чтобы избежать выделения буферов для передачи тех сообщений, которые не могут быть отправлены немедленно. Это противоречие не возникало в гл. 6, поскольку там не использовалось мультиплексирование для реализации множества логических соединений с.помощью одного физического канала, как мы это делаем в данной главе. Здесь указанное противоречие неизбежно, так как невозможно заранее правильно организовать совместное использование буфера ТХ, являющегося разрешением на обмен, отдельными виртуальными каналами.
Проектирование внутренней структуры сетевого уровня обмена
В предыдущем разделе уже были определены внутренние задачи и потоки данных, которые должны быть реализованы на сетевом уровне, поэтому в данном подразделе нашей основной целью будет рассмотрение структуры взаимодействий и исследование функциональных возможностей. Большинство из затрагиваемых вопросов уже обсуждалось в предыдущих главах.
Внутренняя структура может быть частично определена при рассмотрении деталей интерфейса, опущенных на рис. 7.2. Более полный граф, описывающий структуру взаимодействий, показан на рис. 7.4.
По поводу процедур изображенного на рис. 7.4 пакета, реализующего сетевой уровень обмена, необходимо сделать ряд важных замечаний:
При возврате управления из процедуры WAIT_FOR_ CALL один из параметров содержит номер уже подсоединенного виртуального канала. В случае если поступление запроса не ожидается (на что указывает параметр, содержащий адрес абонента), соответствующей реакцией будет немедленное использование процедуры CLEAR.
Для простоты процедура SEND определяется как процедура, в которой обслуживание производится без задержки на ожидание (в предположении, что соответствующие входы внутренних задач не защищены предохранителями) .
У процедуры SEND отсутствует параметр, значение которого могло бы служить разрешением на выполнение обмена. Сообщением о необходимости регулирования потока служит значение параметра, описывающего состояние системы после попытки обращения к этой процедуре.
Рис. 7.4. Конкретизированные интерфейсы пакетов, реализующих протокол Х25.
Для простоты ни одна из процедур не содержит параметров, определяющих величину требуемой задержки.
Читатель должен четко различать два возможных значения слова вызов, как, например, в предложении: «Абонент вызывает процедуру WAIT-FOR-CALL, реализующую ожидание поступления вызова от другого абонента». В первом случае речь идет об обращении, а во втором —■ о запросе; как и понятие совмещения процедур в языке Ада, конкретное значение слова «вызов» становится очевидным из контекста.
Ввиду того что для схем, аналогичных структурной диаграмме, изображенной на рис. 7.4, в предыдущих главах было йри- ведено уже достаточное число соответствующих спецификаций интерфейса, сформулированных на языке Ада, здесь преобразование рисунка в подобную спецификацию мы оставляем читателю в качестве упражнения.
Представленный на рис. 7.5 граф внутренней структуры системы естественным образом вытекает из
схемы интерфейса, изображенной на рис. 7.4;
графа потоков данных, который приведен на рис. 7.3;
стремления к использованию линейных структур взаимО' действий задач;
Рис. 7.5. Внутренняя структура пакета, реализующего сетевой уровень обмена.
результатов проектирования системы AGENT-POOL;
основополагающего проектного решения, согласно которому освободившиеся задачи УВК не ожидают того момента, когда диспетчер выделит им для обслуживания виртуальные каналы, а сразу же с переходом в состояние FREE (СВОБОДЕН) реализуют ожидание вызовов по своим входам.
Номера виртуальных каналов определяют одновременно как виртуальные каналы, так и соответствующие им управляющие задачи.
Формулирование на языке Ада спецификаций интерфейсов, необходимых различным задачам, схематически изображенным
на рис. 7.5, мы оставляем читателю, так как на этом этапе не нужно привлекать никаких новых концепций.
Ниже кратко будут описаны функциональные возможности каждой из уже рассмотренных задач, а также способы их взаимодействий.
Задача DISPATCHER. Диспетчер распределяет свободные задачи между абонентами следующим образом:
при поступлении запросов он возвращает выделенный номер виртуального канала в качестве выходного параметра обращения к входу WAIT-FOR-CALL; этот номер указывает на задачу УВД, которая осуществила прием запроса и обратилась к входу REPORT (если ни один из абонентов не ожидает по входу WAIT-FOR-CALL поступления запроса, то задача УВД, вызвавшая вход REPORT, оповещается об этом путем возврата соответствующего значения параметра состояния системы, в соответствии с которым она отвергнет запрос);
при локальных запросах диспетчер возвращает вызывающему модулю свободный номер ВД в качестве выходного параметра обращения к входу PLACE-CALL; вызывающий модуль (которым является процедура пакета PLACE-CALL) имеет возможность обратиться по этому номеру к свободной задаче УВД и передать ей запрос, вызвав вход CONNECT.
Задачи, реализующие функции управления виртуальными каналами (УВД). Задачи УВД (VCM) реализуют все детали взаимодействий, обеспечиваемых виртуальными каналами. Управляющая задача виртуального канала во многом аналогична задаче FS, выполняющей сервисные функции (напомним, что эта задача принадлежит управляющему пакету логического обмена кадрами, используемому в подсистеме СОММ). Фактически новыми важными вопросами, возникшими в связи с использованием задач VCM, являются их распределение ' между абонентами и организация доступа к ним. Их индивидуальное проектирование не представляет трудностей и не порождает никаких новых проблем. Даждая задача VCM внутренне должна быть структурирована точно так же, как задача FS, на основе протокола равноправного обмена, который реализуется пассивным пакетом, включающим задачи FSM сетевого уровня обмена.
Управление запросами. Процедура PLACE-CALL вначале вызывает вход PLACE-CALL задачи-диспетчера для того, чтобы получить номер виртуального канала. Затем она обращается к входу CONNECT соответствующей задачи VCM и передает ей адрес требуемого абонента. В случае если непосредственно перед этим данная задача VCM приняла запрос на
установление соединения, при возврате управления из оператора приема CONNECT параметр, описывающий состояние, будет указывать на то, что канал больше не доступен. Если же канал доступен, процедура PLACE-CALL обратится к выходу WAIT; тем временем задача VCM отправит пакет, содержащий запрос на установление соединения. Как только этот пакет будет передан по каналу путем обращения к входу PUT, будет выполнен оператор приема, принадлежащий входу WAIT, и абонент получит возможность использовать виртуальный канал для обмена данными.
Свободная задача VCM, получив по входу PUT пакет, содержащий запрос на установление соединения, передает его и уведомляет диспетчера о поступлении запроса (путем вызова входа REPORT). Если требуемый абонент отсутствует, то при возврате из процедуры REPORT задаче посылается уведомление об этом путем передачи соответствующего значения параметра состояния системы, которое позволяет ей отвергнуть запрос. В противном случае диспетчером выполняется оператор приема, принадлежащий входу WAIT-FOR-CALL, и абоненту передается адрес отправителя и номер виртуального канала. Если в момент поступления запросного пакета задача VCM занята, он отвергается в соответствии с правилами протокола Х.25, касающимися столкновения запросов.
При поступлении запроса CLEAR (РАЗЪЕДИНИТЬ) от локального абонента задача VCM прекращает передачу информации, пересылает пакет с запросом на разъединение и ожидает поступления подтверждающего сообщения для перехода в состояние FREE. Если пакет с запросом на разъединение поступил от удаленного абонента, эта задача действует аналогичным образом: прекращает передачу информации, пересылает пакет, содержащий подтверждение разъединения, и после этого сразу сообщает диспетчеру о своем свободном состоянии путем вызова входа REPORT. В любом случае, когда задача VCM прекращает передачу данных, все очереди, содержащие информационные пакеты, аннулируются и все входящие пакеты, поступающие на вход PUT, отвергаются до тех пор, пока не будет получен новый запрос на соединение.
Передача данных. Все логическое управление, а также структуры данных, связанные с передачей, приемом, подтверждением приема и повторной передачей пакетов данных, полностью сосредоточены в задаче VCM. Все обрабатываемые ею пакеты помещаются в две очереди — очередь пакетов на повторную передачу, где хранятся экземпляры отправленных пакетов, по которым нет подтверждений приема, и очередь поступивших, но еще не обработанных пакетов. Основными факторами, влияющими на функционирование задачи, являются состояние
задачи, включающее состояние виртуального канала, длины обеих очередей и время передачи пакета с максимальной задержкой подтверждения приема. Внутренняя структура задачи VCM будет полностью аналогична той, которая была использована для реализации сервисных функций при логическом обмене кадрами в подсистеме СОММ.
В состоянии передачи данных вызовы входов SEND, PUT и CLEAR принимаются задачей VCM в любой момент времени, вызов же входа RCVE — только в том случае, если очередь на прием не пуста. В результате выполнения оператора приема по некоторому входу задача VCM реализует требуемые операции, корректируя при этом очереди и передавая информационные пакеты, а затем управление возвращается оператору отбора для организации ожидания следующего вызова. В тех случаях, когда длина одной из очередей на повторную передачу или прием достигает максимума, определяемого величиной соответствующего окна, регулирование информационного потока при передаче данных будет осуществляться с вышестоящего уровня, а при приеме — с нижестоящего. Регулирование информационного потока при передаче проводится задачей VCM путем завершения рандеву без выполнения оператора приема SEND, в результате чего очередной пакет отвергается; при возврате из процедуры значение параметра STATUS служит вызывающему модулю указанием на возникновение условий регулирования. Регулирование потока данных при приеме осуществляется аналогичным образом путем прекращения рандеву по входу PUT, в результате чего пакет отвергается (однако управляющие пакеты принимаются в любом случае).
Повторная передача информационных пакетов выполняется точно так же, как и в подсистеме СОММ. В каждый пакет заносится отметка о времени последней передачи. Первым в очереди пакетов на повторную передачу стоит пакет, который находится в очереди дольше всех других и, следовательно, требует передачи первым. Перед обращением к оператору отбора задача определяет, сколько времени ожидает подтверждения пакет, стоящий во главе указанной очереди, и устанавливает соответствующее значение параметра оператора задержки. Если до того момента, как истечет установленное время, вызов соответствующего входа не будет принят, то выполняется альтернатива задержки и неквитированные пакеты будут переданы еще раз. В случае если вызов требуемого входа будет принят, параметр альтернативы задержки будет соответствующим образом скорректирован.
Задачи ROUTER.JN, ROUTTER-OUT и BUFFER. Задача ROUTER_IN ожидает поступления кадров данных, передаваемых пакетом управления канальным уровнем обмена, осуще-
ствляет их декодирование, формирует из них информационный пакет для конкретного виртуального канала и, наконец, вызывает вход PUT соответствующей задачи VCM для передачи этого пакета абоненту. В зависимости от значения параметра STATUS, возвращаемого оператором приема PUT, по окончании рандеву может возникнуть необходимость отвергнуть пакет (возвратить его в пул свободных буферов кадров); такая ситуация может возникнуть, либо если задача VCM в данный момент осуществляет регулирование входящего информационного потока, либо если в момент поступления пакета, реализующего запрос на установление соединения, задача не находится в со* стоянии FREE.
Задача ROUTER-OUT выполняет функции простой транспортировки данных, осуществляя перенос информации за один раз (один пакет) между задачей BUFFER и пакетом LINK при наличии у него разрешения в виде буфера ТХ.
Задача BUFFER реализует функции накопления исходящих пакетов, предназначенных для передачи по виртуальным каналам.
Заключительные замечания к проекту
Большинство замечаний, сделанных в гл. 6 при обсуждении проекта подсистемы СОММ, справедливы и в отношении рассматриваемого проекта и их нет нужды повторять.
Проектное решение в том виде, в котором оно отображено на рис. 7.5, возникло после нескольких неудачных попыток упростить сложную внутреннюю логику задачи-диспетчера путем введения несколько иной структуры системы обмена. При реализации этой структуры требовалось, чтобы пакеты, содержащие запросы на установление соединения, поступали сначала в задачу-диспетчер, а не в свободную задачу VCM. В результате возникающая трехэтапная схема взаимодействия (задачи ROUTER IN, выделенной задачи VCM и абонента) становилась слишком громоздкой для составления ее описания. Независимо от причин, по которым возникла такая структура, внутренняя логика задачи-диспетчера оказалась чрезвычайно сложной по сравнению с достаточно простой проблемой распределения виртуальных каналов. Существует одно контрольное правило, действующее при проектировании систем и написании программ, которое часто оказывается полезным в подобных ситуациях. Оно гласит: когда пытаются сказать что-либо трудно формулируемое, возможно, что высказываемая мысль ошибочна. Как только мы остановились на схеме, изображенной на рис. 7.5, все проблемы, связанные с внутренней логикой задачи-диспетчера, сразу исчезли. Значит, дело здесь в том, что
мы пытались высказать ошибочную мысль! Структура, при попытке использования которой возникли отмеченные выше трудности, согласно критериям гл. 6, обладает меньшей степенью модульности, чем схема, изображенная на рис. 7.5. Следовательно, если бы мы приняли в нашем проекте указанную выше структуру, то у нас могли бы появиться дополнительные проблемы.
Упомянутые неудобства, связанные с использованием этой схемы, возникли главным образом из-за того, что было реализовано фиксированное назначение номеров виртуальных каналов задачам VCM. Однако и простота решения, приведенного на рис. 7.5, тоже определяется в первую очередь использованием такого фиксированного распределения. Динамическое распределение номеров может потребовать совершенно иного подхода.
Дополнения к проекту
На практике интерфейсные процедуры пакета управления сетевым уровнем обмена, реализующие ожидание событий, должны иметь параметры, с помощью которых задаются допустимые интервалы простоя; данное требование может быть реализовано путем включения в эти интерфейсные процедуры временных вызовов соответствующих входов внутренних задач, что схематически изображено на рис. 7.6. Логика функционирования внутренних задач должна гарантировать невозмож-
Рис. 7.6. Внутренние сопряжения на сетевом уровне, используемые для реализации механизма временных задержек (показаны не все процедуры и входы задач). - , - .
Параметр состоянияПараметр состоянияРассылка уведомлений о событиях всем абонентамРассылка уведомлений о событиях всем абонентамЧтобы учесть тот случай, когда абоненты ожидают появления других событий (например, поступления запросов на соединение
Параметр состояния
Параметр состояния
Рассылка уведомлений о событиях всем абонентам
Рассылка уведомлений о событиях всем абонентам
или получение пакетов данных), требуется использование условных вызовов входов. Абоненты, попадая в одно из этих состояний, должны иметь дополнительные возможности обнаружения событий, поэтому повторный вызов входа REPORT осуществляться не' будет
Рис. 7.7. Схема уведомления абонентов о событиях, происходящих на сетевом уровне обмена( показаны не все процедуры и входы задач).Рис. 7.7. Схема уведомления абонентов о событиях, происходящих на сетевом уровне обмена( показаны не все процедуры и входы задач).Параметр состоянияПараметр состоянияПакетPACKETLAYERПакетPACKETLAYERкость такой ситуации, когда они будут «застревать» в состоянии ожидания временного вызова, поскольку это приводило бы к тупику. Напомним, что тупиковая ситуация может возникнуть в том случае, если временной вызов входа будет принят задачей в связи с определенным значением относящегося к этому входу атрибута COUNT (ЧИСЛО ВЫЗОВОВ), а в конечном итоге окажется, что в промежутке между вычислением значения атрибута и приемом вызова истечет время, отведенное на ожидание.
Рис. 7.7. Схема уведомления абонентов о событиях, происходящих на сетевом уровне обмена( показаны не все процедуры и входы задач).
Рис. 7.7. Схема уведомления абонентов о событиях, происходящих на сетевом уровне обмена( показаны не все процедуры и входы задач).
Параметр состояния
Параметр состояния
Пакет
PACKETLAYER
Пакет
PACKETLAYER
В разд. 7.3 мы совсем не касались вопроса о том, как уведомлять абонентов о начале регулирования информационного потока при пакетной передаче. Неявное предположение заключалось в том, что абонент, у которого передача пакетов была заблокирована, должен просто повторять в подходящие моменты времени вызов SEND до тех пор, пока пакет не будет принят. Однако такое решение нельзя считать удовлетвори-
тельным. Дело в том, что выделение слишком короткого временного интервала на осуществление повторной передачи может привести к чрезмерно большим расходам процессорного времени на ожидание сброса сигнала занятости, а выделение слишком длинного интервала снижает пропускную способность системы до неприемлемого уровня. В любом из этих случаев логика существенно усложняется, поскольку в модули должны быть включены программы, осуществляющие повторную передачу данных.
На рис. 7.7 представлен возможный вариант организации уведомления абонентов о регулировании очереди входящих пакетов, не требующий повторной передачи информации. Задача CHECKER (КОНТРОЛЕР) вызывает новый вход CHECK (ПРОВЕРКА) задачи-диспетчера и ожидает поступления сообщений о событиях, происходящих на сетевом уровне обмена. Единственным рассматриваемым здесь существенным событием является начало регулирования очереди входящих пакетов, передаваемых по виртуальному каналу, но, вообще говоря, возможна регистрация и других событий. При возникновении интересующего нас события задача CHECKER уведомляет о нем абонентов, реализуя условные вызовы входов. Указанные обращения должны быть условными потому, что абоненты в данный момент могут ожидать появления какого-либо другого события.
Другой подход заключается в разработке некоторого механизма предоставления разрешения на передачу информации между абонентом и пакетом управления сетевым уровнем обмена.
Альтернативные проектные решения
Полученный в процессе проектирования пакет, реализующий функции сетевого уровня протокола Х.25, содержит N + 4 задачи, где N — число виртуальных каналов. Ниже рассматривается вариант использования меньшего числа задач.
Вместо того чтобы выделять каждому виртуальному каналу свою задачу У В К, можно использовать одну или две задачи, функционирующие на сетевом уровне обмена и управляющие работой всех виртуальных каналов сразу; при этом либо одна главная задача управляет всеми каналами, либо вводится пара задач, одна из которых осуществляет функции установления связи, а вторая — передачу данных. В этих задачах должны храниться в явном виде таблицы состояниях всех виртуальных каналов и предусматриваться счетчики передаваемых пакетов данных. Кроме того, требуются еще задачи ROUTER-IN и ROUTER_OUT, однако отпадает необходимость в использовании задачи DISPATCHER. Задача BUFFER требуется только
в том случае, если управление вызовами и передача данных осуществляются двумя разными задачами. Таким образом, полное число задач, необходимых для реализации информационного обмена по виртуальным каналам, заключено между тремя и пятью. Эти задачи должны иметь несколько входов с тем, чтобы прием вызовов мог осуществляться ими по разным виртуальным каналам, находящимся в различных состояниях, независимо.
Как уже отмечалось в гл. 6, выбор подходящего решения среди проектов, предусматривающих использование большого или малого числа задач, может быть осуществлен на основе количественных сопоставлений и зависит от конкретной реализации, однако рассмотрение этих вопросов выходит далеко за рамки проблем, которым посвящена данная книга. Тем не менее, как уже упоминалось в гл. 6 и еще будет обсуждаться ниже, некоторые качественные суждения все же возможны.
Важным доводом в пользу принятия метода, предусматривающего для каждого виртуального канала свою задачу, служит достижимая при этом модульность. При разработке любой системы концептуальная ясность становится неотъемлемой особенностью проекта лишь тогда, когда форма ее реализации определяется функциональным назначением. Если это назначение отображается самой формой представления проектных решений, то их наверняка легче понять и реализовать. Мы утверждаем, что подход, связанный с выделением каждому виртуальному каналу своей задачи, представляет как раз пример такого рода. Виртуальный канал, с одной стороны, логически независим от остальных каналов, а с другой, состязается с ними за обладание общими ресурсами, и поэтому вполне естественно, что он управляется некоторой задачей. Необходимо заметить, что логика программы оказывается более простой, если виртуальные каналы управляются раздельно, каждый своей задачей, как, например, в случае реакции на события, связанные с исчерпанием выделенного временного интервала. Для реализации подобного механизма меньшим числом задач необходимо использование более сложной внутренней логики или специальных структур данных, с помощью которых можно было бы реализовать альтернативу задержки в операторе отбора и по истечении временного интервала выполнить требуемые действия по обработке пакета или установлению соединения.
Другим возможным вариантом является использование предыдущего метода, но с одним дополнением: в этом варианте диспетчер имеет возможность порождать задачи динамически — по требованию, и эти задачи существуют только в сеансе взаимодействия двух абонентов. В данном случае, согласно прин-
ципам организации динамического доступа в прямом направлении, обсуждавшимся в гл. 5, абоненту должен передаваться идентификатор задачи, управляющей его виртуальным каналом.-
Подход, основанный на динамическом порождении задач,, позволяет избежать ненужного связывания ресурсов памяти хранением контекстных таблиц и стеков незанятых задач. При таком подходе для организации доступа задачи ROUTER IN к задачам VCM необходимо, чтобы в задаче-диспетчере велась специальная таблица, содержащая ссылочные переменные этих задач.
Когда задача VCM прекращает свою работу, задача-диспетчер должна уведомляться о том, что данный канал свободен; тогда при повторном использовании того же канала для управления им можно будет создать новую задачу; следовательно, все задачи VCM должны обращаться к входу задачи-диспетчера DISPATCHER-FREE (КАНАЛ-СВОБОДЕН). Более того, теперь мы должны принять ранее отвергнутую схему взаимодействий, в соответствии с которой задача ROUTER_IN пересылает входящие пакеты с запросами на установление соединения диспетчеру.
Необходимо позаботиться также, чтобы задача ROUTERIN не делала попыток получить доступ к задаче VCM, уже закончившей работу. Однако, как будет показано ниже, подобная ситуация может все же возникнуть из-за состязания между этими двумя задачами. Задача ROUTER-IN могла получить ссылочную переменную, указывающую на некоторую задачу VCM, в промежутке времени между уведомлением диспетчера об освобождении канала и завершении ее собственной работы, и моментом, когда диспетчер обновляет свою внутреннюю таблицу. Указанная проблема, конечно, может быть решена, но ценой увеличения сложности системы; при этом возможны два пути ее решения:
Спроектировать задачу VCM таким образом, чтобы после уведомления ею диспетчера об освобождении канала эта задача переходила к выполнению оператора отбора, который содержит альтернативу задержки, реализующую выборочное ожидание на всех ее входах. Тогда при обращении к любому входу при посредничестве управляющего модуля последний будет возвращать вызывающему модулю уже измененное значение параметра состояния системы. По истечении установленного времени задержки задача VCM завершает свою работу.
В каждую задачу, которая может иметь рандеву с задачей VCM, включить локальный блок обработки исключений, который позволит обнаруживать эти ошибочные
Рис. 7.8. Неиерархическая структура пакета, полученная из иерархической структуры путем ее реорганизации.
ситуации, если они возникнут, и ликвидировать их последствия.
Совершенно очевидно, что подход, основанный на динамическом порождении задач, оказывается более сложным.
Следует отметить, что всюду в гл. 6 и 7 мы имели дело только с нисходящими управляющими структурами, которые появлялись в процессе проектирования; в этих схемах модули каждого уровня для осуществления любых взаимодействий с остальной частью системы обращаются непосредственно к следующему уровню. Первоначально этот подход был предложен в гл. 6 для построения многоуровневой системы, поскольку, во-первых, хорошо знаком, а во-вторых, позволяет избежать возникновения тупиков благодаря очень аккуратному использованию вызовов между уровнями в обоих направлениях — снизу вверх и сверху вниз. Однако в наши намерения отнюдь не входит пропагандирование нисходящих управляющих структур как лучших или единственно возможных.
В равной мере приемлемо и использование симметричных управляющих структур, отличие которых от нисходящих струк-
тур может заключаться лишь в некоторых «косметических» деталях организации пакетов, что иллюстрирует рис. 7.8 (естественно получающийся из рис. 6.4,6). Если модифицировать нисходящие схемы реализации протокола X. 25 путем изменения границ между уровнями, то взаимодействие между пакетами может быть сделано двусторонним без нарушения характера взаимодействий задач. В отличие от рис. 7.5 задача ROUTERIN на рис. 7.8 перенесена в пакет управления канальным уровнем обмена, а в пакет, описывающий работу сетевого уровня, добавлена новая интерфейсная процедура PUT. Эта процедура обеспечивает теперь декодирование кадров данных и передает пакеты внутренним задачам. Прежде эти функции осуществляла задача ROUTER-IN, которой не требуется различать пакеты, поступающие по разным виртуальным каналам; она функционирует просто как задача, осуществляющая транспортировку информационных кадров.
Проектирование еще одной альтернативной симметричной схемы взаимодействий с использованием буферизующей задачи вместо задач-курьеров может быть осуществлено на основе рис. 6.4,8. Разработку этой схемы мы оставляем читателю в качестве упражнения.
Проектирование семиуровневой модели взаимодействия открытых систем
В этом разделе кратко обсуждается вопрос о том, каким образом вышеизложенный подход может быть использован при проектировании семиуровневой модели взаимодействия открытых систем (ВОС), предложенной Международной организацией по стандартизации. Эта модель базируется на концепции объектов, предоставляющих некоторые виды услуг объектам вышестоящего уровня. Обслуживающие объекты взаимодействуют с дистанционными равноправными объектами путем обмена протокольными блоками данных, реализуемого нижним уровнем.
Хотя управление физическим обменом протокольными блоками может осуществляться только с помощью объектов нижнего уровня, логическая структура этих блоков может быть скрытой. Скрытность ПБД обеспечивается тем, что протокольные блоки данных верхних уровней вложены в аналогичные блоки нижних уровней точно так же, как протокольные блоки данных сетевого уровня обмена протокола X. 25 (пакеты) вложены в протокольные блоки данных канального уровня (кадры).
Считается, что у каждого объекта имеется точка доступа к сервисным функциям (идентификатор объекта) и что он управляет соединениями, аналогичными виртуальным каналам
протокола Х.25. Обслуживание обеспечивается с помощью сервисных примитивов, с каждым из которых могут быть связаны соответствующие параметры. Сервисные примитивы могут организовывать движение потока данных между объектами в двух направлениях — сверху вниз и снизу вверх.
Точно так же как в случае протокола Х.25, спецификация ВОС, определяет только протокольные блоки данных, порядок приема и передачи и результаты, но не описывает структуру системы, реализующей данный протокол обмена.
При использовании нашего подхода для проектирования модели ВОС объекты представляются активными пакетами, а точками доступа к сервису будут имена пакетов. Реализация примитивов будет осуществляться с помощью видимых процедур спецификаций пакетов.
Опираясь на опыт, накопленный нами при рассмотрении предыдущих примеров, можно дать следующие рекомендации по проектированию модели ВОС, реализующей нисходящую управляющую структуру согласно схеме, изображенной на рис. 6.3, б:
Создавать каждый уровень модели с использованием активного пакета.
Реализовывать каждый объект внутри уровня с помощью видимого активного пакета, вызываемого извне.
Определять сервисные примитивы в контексте видимых процедур пакетов, снабженных необходимыми параметрами. Для придания большей четкости управляющей структуре примитивы, используемые в разных состояниях протокола, следует реализовывать отдельными процедурами.
В пакете каждого обслуживаемого объекта необходимо иметь по крайней мере две задачи — одну для управления служебным интерфейсом, а другую —для транспортировки управляющих воздействий с нижестоящего уровня по направлению снизу вверх (в предположении, что взаимодействие с нижними уровнями осуществляется в дуплексном режиме и может быть связано с ожиданием). Если осуществление взаимодействий, направленных сверху вниз, может быть сопряжено с условным ожиданием, то необходимо вводить дополнительную задачу- курьер, выполняющую их «транспортировку».
« Каждое соединение, организуемое на некотором уровне системы, требует введения по крайней мере одной задачи для реализации правил протокола, касающихся установления связи, использования канала и разъединения.
При установлении множественных соединений необходимо предусматривать буферизующую задачу, которая на-
капливает сообщения, идущие в направлении сверху вниз, для передачи их задаче-курьеру (если такая задача вообще существует).
Проектирование системы с протоколом Х.25, проведенное выше, служит хорошим примером практического применения этих рекомендаций. Читатели, которые знакомы с соглашениями, принятыми в модели ВОС, могут заметить, однако, что в указанном примере существует целый ряд деталей, не соответствующих структуре ВОС. Например, процедура WAIT- FOR-CALL вообще должна не обеспечивать установление соединения при поступлении вызова, а лишь сигнализировать о появлении входящего пакета; для подтверждения приема вызова необходимо иметь отдельную процедуру ACCEPT-CALL (ПРИЕМ-ВЫЗОВА). Более того, в некоторых случаях (например, при реализации транспортного уровня модели) идентификаторы каналов должны динамически пересылаться задачам, управляющим их работой в динамическом режиме.
Совершенно очевидно, что можно было бы привести аналогичные рекомендации по проектированию модели ВОС, которая реализовывала бы симметричную управляющую структуру в соответствии со схемой, изображенной на рис. 6.4, в. Разработку такого проекта мы тоже оставляем читателю в качестве упражнения.
Проведенное выше обсуждение позволило нам с трудом рассмотреть лишь верхушку айсберга, именуемого моделью ВОС. Многие важные системные вопросы проектирования и реализации ВОС, не затронутые в ходе обсуждения, являются предметом исследований, которые проводятся в лаборатории, руководимой автором этой книги.
Заключение
Мы подошли к разделу, который завершает гл. 7, часть III и всю книгу. В третьей ее части было показано, как в процессе проектирования исследуются взаимосвязи и достигаются соответствующие компромиссы между обеспечением модульности, надежности и структурированности систем при помощи графических представлений и методологии проектирования, основанной на использовании языка Ада. Графические средства этого языка в сочетании с изложенной методологией служат хорошей основой для коллективного обсуждения проектных решений. Процесс разработки систем с применением указанных средств может носить относительно неформальный характер и предоставлять разработчику определенную свободу. Однако конечный результат, а именно набор структурных графов, снабженных необходимыми комментариями, является уже формализованным
описанием в терминах языка Ада и может использоваться для написания соответствующих Ада-программ почти механически.
Характерной особенностью всех проектов, рассмотренных в части III (и всюду в данной книге), является организация в соответствующих пакетах и задачах раздельных процедур и входов для разных сервисных функций пакетов и задач. Применительно к задачам было показано, каким образом взаимодействия различного рода могут реализовываться с использованием разных входов в рамках так называемой линейной структуры взаимодействий, которая не допускает использования механизма вложенных рандеву. Такой подход дает возможность разработчику системы, оперирующему со структурными графами, четко показать различный характер требуемой обработки разных запросов. Кроме того, применительно к задачам оказывается возможным отобразить на граф-схемах механизмы ожидания, используемые в межзадачном интерфейсе, в результате чего гарантируется достаточно детальное описание системы на уровне структурного графа, который в свою очередь позволяет обосновывать окончательные проектные решения, не прибегая к текстам программ.
В общем виде мы показали, как в целях достижения необходимой модульности одна или несколько задач могут быть успешно скрыты в теле пакета.
Поскольку весь материал ориентирован на описание процесса проектирования, язык Ада в части III послужил в первую очередь семантической основой графической нотации, и примерам реальных программ, написанных на языке Ада, отведено не слишком много места.
Примеры, включенные в часть III и иллюстрирующие изложенный в книге подход к проектированию систем, представляют самостоятельный интерес, так как помогают понять и решить многие проблемы проектирования систем, функционирование которых осуществляется на основе протоколов информационного обмена. Широкие возможности предложенного метода достаточно хорошо иллюстрируются тем, что решения всех этих проблем легко представляются в компактном и понятном виде.
Задания для самостоятельного выполнения
Глава 2
Спроектируйте заново изображенный на рис. 2.9 стековый пакет так, чтобы он имел единственную интерфейсную процедуру, подобную написанной на Паскале (см. рис. 2.5,6). Перепишите тело пакета (рис. 2.4) с использованием языка Ада. Прокомментируйте различия между новым и старым пакетами в отношении простоты построения, модульности и функциональных возможностей.
Напишите на Паскале программу, реализующую стековый пакет, следуя схеме, которая представлена на рис. 2.5, б. Перечислите существенные различия между программой, написанной на Паскале, и соответствующей Ада-программой. Внимательно проанализируйте текст программы и ее поведение во время выполнения. Какое значение при прогоне имеет наличие пакета в программе, написанной на языке Ада, и его отсутствие в программе на Паскале?
Используя в качестве основы буферизующую задачу, которая схематически представлена на рис. 2.7 и 2.8, спроектируйте и запрограммируйте на языке Ада ее новую версию, предназначенную для организации работы с буферами строк. Новая задача должна иметь два входа: WRITE — для записи символов и READ—для чтения строк. Как и прежде, вход WRITE будет закрыт до тех пор, пока все буферы не освободятся, а вход READ — до тех пор, пока не будет сформирована целая строка. Предполагается также, что строки имеют переменную длину с ограничением по максимуму и оканчиваются специальным символом.
Предположим, что программист по соображениям удобства вместо реализации пассивного пакета, используемого единственной задачей, решает спроектировать для работы с буферами задачу, управляющую доступом к буферам. Строго говоря, работа с буферами при этом будет организована неправильно. При корректном использовании буферов входы READ и WRITE должны вызываться разными задачами, а в предполагаемом проекте обращение к ним должна выполнять одна и та же задача. Какого типа задачи могли бы быть использованы подобным образом — иллюстрируемые рис. 2.7 и 2.8 или задача^
описанная в п. 2.3? Какие типы задач для этого непригодны? Объясните, почему.
Спроектируйте и запрограммируйте на языке Ада пассивный пакет для работы с буферами, проект которого описан в п. 2.4. Согласно п. 2.3, этот пакет должен включать процедуры для записи символов и чтения строк. Однако формирование условия, разрешающего доступ к строке символов, должно быть организовано по-другому.
Для буферизующей задачи (рис. 2.7), реализованной согласно схеме рис. 2.8, укажите минимальное и максимальное числа требуемых контекстных переключений при передаче одного символа от отправителя к адресату, предполагая, что в системе функционируют только те три задачи, которые приведены на рисунке. Объясните решение.
Перепишите заново стековый пакет, приведенный на рис. 2.4, определяя процедуры PUSH и POP с помощью заглушек, согласно рис. 2.12. (Метод, иллюстрируемый рис. 2.12, может быть применен не только к вложенным пакетам, но и к процедурам пакета.)
Исследуйте различные способы обработки прерываний, применяемые в разных многозадачных системах, сравнив их детально с методом, использующим концепции языка Ада (рис. 2.15).
(а) Запрограммируйте на языке Ада спецификацию и тело задачи, реализующей функции общего семафора со счетчиком. Семафоры используются как средство синхронизации задач, предотвращающее потерю сигналов, которыми они обмениваются. Такой семафор общего типа реализуется с помощью неделимых примитивов WAIT и SIGNAL внутреннего счетчика, позволяющего оценивать разность между числом задач, посылающих сигналы, и числом задач, ожидающих их поступления, и, наконец, очереди ожидающих задач с дисциплиной обслуживания «первым пришел — первым обслужен». Задача, вызывающая WAIT, попадает в указанную очередь и блокируется в том случае, если ранее было зарегистрировано большее число обращений к примитиву WAIT, чем к SIGNAL; в противном случае ее выполнение продолжается без задержки. Задача, стоящая на первом месте в очереди ожидающих, будет выполняться после того как поступит очередной вызов примитива SIGNAL.
Предполагается, что после вызова примитива SIGNAL выполнение вызывающей задачи продолжается без блокировки (исключая, возможно, тот случай, когда в однопроцессорной системе, реализующей приоритетное обслуживание, задача, стоящая во главе указанной очереди, имеет более высокий приоритет, чем задача, посылающая сигнал). Подобным же образом вызов входа WAIT не должен приводить к блокировке, ес-
ли ранее было зарегистрировано достаточное число вызовов входа SIGNAL. Объясните, каким образом это предположение нарушается в вашей Ада-программе; опишите два способа реализации, в которых подобное нарушение могло бы повлиять на поведение во времени задач, обращающихся к семафорам.
Глава 3
Изобразите структурные графы для буферизующих задач, которые рассматривались в качестве примеров в гл. 2, используя графические обозначения, приведенные на рис. 3.2 и 3.3.
Для буферизующих задач приведите конкретные примеры структурных задержек, задержек, вызванных перегрузкой, и скрытых задержек. .
Рис. 3.10 и 3.11 служат иллюстрацией образного представления механизма рандеву в языке Ада на примере взаимодействий людей. Однако они иллюстрируют не все возможные случаи (согласно графическим обозначениям на рис. 3.2 и 3.3). Приведите новые схемы, соответствующие рис. 3.10 и 3.11, для условного и временного вызовов входов, а также для оператора отбора с альтернативой задержки и объясните их смысл.
Изобразите структурные графы, показав все возможные формы взаимодействия главного и подчиненного процессов, и прокомментируйте различия между ними (см. подразд. 3.3.1). Возникают ли при этом случаи, когда подчиненная задача может быть заменена пассивным пакетом? Объясните свой ответ.
Принимая во внимание определение функциональных типов задач, данное в подразд. 3.3.1, приведите примеры использования задач этих типов на рис. 3.6,6. Выполняет ли задача- секретарь, указанная на рис. 3.6,6, функции секретаря системы в соответствии с определением, данным в подразд. 3.3.1 ? Какие функциональные типы задач не представлены на рис. 3.6, б ? Можете ли вы дополнить рисунок, найдя в нем место этим задачам?
Рассмотрите рис. 3.14, в, на котором изображен активный стековый пакет, содержащий вложенную задачу-планировщик ресурсов. Приведите полную структурную диаграмму для системы задач, использующих этот пакет, и затем объясните проявляющиеся в рабочем режиме фундаментальные различия между характером задач, изображенных на этом рисунке, и природой данного пакета. В каком смысле можно было бы сказать, что пакет «исчезает» в процессе выполнения программы, оставляя место задачам? Какую роль в этом случае играет указанный пакет в ходе выполнения задач? В каком смысле можно говорить об отсутствии различий в рабочем режиме между
вложенным планировщиком (рис. 3.14, в) и отдельным планировщиком (рис. 3.14,5).
Рассмотрите рис. 3.17, иллюстрирующий косвенное взаимодействие различных задач через буферизующую задачу. Имеются ли существенные различия в эффективности между методом, использующим единственную буферизующую задачу (рис. 3.17, а), и методом, использующим несколько таких задач, одну для каждого абонента (рис. 3.17,6)?
Рассмотрите рис. 3.19, на котором схематически представлена задача, реализующая сервисные функции на основе приоритетов. Объясните, почему существует теоретическая возможность приема обращений к входам в порядке, отличном от предписываемого приоритетами. При каких состояниях операционного окружения системы такие ситуации были бы возможны?
Предполагается, что одна высокоприоритетная задача вызывает вход задачи, реализующей сервисные функции (см. рис. 3.19), используя оператор временного вызова, а остальные задачи, имеющие средний и низкий приоритет, обращаются к ее другим входам. Постройте временную диаграмму, иллюстрирующую чередование последовательностей событий, соответствующих точкам синхронизации, когда сервисная задача оказывается не в состоянии обслужить задачи, обращающиеся к ее средне- и низкоприоритетному входам, несмотря на то что очередь вызовов высокоприоритетного входа пуста.
Приведите временные диаграммы, показывающие чередующиеся активности различных задач, взаимодействующих через задачу-курьер, выполняющую транспортировку данных (рис. 3.21,5), или с помощью задачи, осуществляющей их буферизацию (рис. 3.21, з). Прокомментируйте различия.
Предполагается, что имеются четыре задачи, обменивающиеся данными произвольным образом. Изобразите структурные графы, иллюстрирующие схемы взаимодействий с использованием либо задачи-курьера (рис. 3.21,5), либо буферизующей задачи (рис. 3.21, з). Сравните два подхода. Будут ли результаты сравнения существенно отличаться друг от друга, если четыре задачи взаимодействуют не произвольным образом, а так, что каждая взаимодействует только с двумя из остальных трех?
Предполагается, что спроектированная система представляет собой набор задач, которые для ее успешного функционирования должны взаимодействовать друг с другом. Приведите примеры, показывающие, что использование произвольных комбинаций различных схем взаимодействия, изображенных на рис. 3.21, может приводить к тупику.
Напишите на псевдокоде программу, показывающую, каким образом задача SENDER (см. рис. 3.22,6) должна использовать механизм предоставления разрешения на обмен, реализуемый задачей TARGET.
Опишите на псевдокоде, как должны взаимодействовать задачи SENDER и TARGET (см. рис. 3.22, в), для того чтобы осуществлять прием и передачу элементов данных и предоставлять разрешение на обмен.
Используя пример, описывающий работу банка (рис. 3.23—3.25), постройте структурный граф и напишите соответствующую программу на псевдокоде, чтобы проиллюстрировать, как кассиры могут динамически запрашивать у диспетчера номера окошек, которые они обслуживают.
Даны две задачи, каждая из которых имеет один вход и может осуществлять вызов другой. Напишите на псевдокоде тела этих задач для иллюстрации двух ситуаций: 1) когда тупик возникает обязательно и 2) когда состояние тупика не возникает вообще.
Предполагается, что в некоторой задаче имеются два входа. Четко объясните, какое значение для вызывающих задач имеют перечисленные ниже различные механизмы приема вызовов входов (используя, если нужно, временные диаграммы):
упорядоченный прием вызовов;
прием вызовов с помощью оператора отбора;
прием одного вызова входа внутри критической секции, связанной с другим входом.
Напишите на псевдокоде программы, реализующие различные механизмы организации приема вызовов, указанные в п. 3.17.
Глава 4
На рис. 4.10 схематически изображены два механизма взаимодействия задачи CONTROL с некоторым числом подчиненных задач SLAVE: один — когда вызовы осуществляют задачи SLAVE, и второй — когда вызовы осуществляются задачей CONTROL. При каких условиях задачи SLAVE с целью увеличения эффективности системы можно было бы заменить процедурами? В каком случае оказывается более эффективным использование задач?
Напишите на псевдокоде тела задач LIFE и KEYBOARD, применяемых в системе LIFE. Используйте в задаче KEYBOARD буфер опережающего ввода символов.
Для определения конечных автоматов, описывающих работу модуля дешифратора команд в системе LIFE (рис. 4.17), используйте соответствующие составные значения
переменных регулярного типа. Предложите более эффективный способ представления конечных автоматов.
Разработайте новые структурные графы для случая, когда модуль обработки команд, лежащий в основе системы LIFE, строится на декодировании символов, а не слов. Сравните этот проект с проектом, описанным в гл. 4.
Напишите на псевдокоде тело пакета управления логическим обменом в системе FORMS и тело вложенного пакета редактирования.
Объясните, какие изменения необходимо внести в проект системы FORMS для того, чтобы реализовать показанные пунктиром состояния и переходы конечного автомата, описывающего работу командного процессора на рис. 4.2.
Нарисуйте временную диаграмму, показывающую последовательность событий, в результате которой задача системы FORMS, управляющая работой печатающего устройства, не может начать вывод требуемых строк, пока оператор не нажмет соответствующую клавишу (см. рис. 4.25, а и сопутствующий текст).
Спроектируйте заново систему FORMS, применяя буферизующую задачу вместо задачи-курьера. Отправным пунктом может послужить соображение о том, что каждая основная задача в системе будет иметь свою собственную буферизующую задачу, с помощью которой она может осуществлять все взаимодействия с другими задачами системы. Двумя главными задачами в системе FORMS являются задача, выполняющая обработку событий, и задача, управляющая работой печатающего устройства. Сравните ваш проект с проектом, описанным в гл. 4.
Напишите на псевдокоде тела пакета распознавателя команд, и пакета, управляющего работой командного процессора, как внутренних пакетов задачи обработки событий (рис. 4.25).
Модифицируйте проект системы FORMS так, чтобы параллельное выполнение печати и редактирования достигалось с помощью двойной буферизации. С этой целью необходимо использовать буферы двух типов: 1) для ввода и редактирования данных, 2) для фоновой печати ранее введенной информации. Интерфейс оператора с системой должен быть расширен путем добавления команды печати. Для иллюстрации нового подхода изобразите структурный граф, соответствующий рис. 4.25, а.
Начертите полный структурный граф системы FORMS, разработанной в гл. 4, изобразив на рисунке все ее компоненты. Кроме пакетов и задач, включите в него также и обрабатываемые данные.
Постройте структурный граф, показывающий, каким образом в систему FORMS может быть добавлен интерфейс с файловой системой.
Рассмотрите расширенную версию системы FORMS, представив ее в виде набора подсистем управления пультом оператора, устройством печати и файлами. Исходя из соображений модульности, было бы желательно реализовать каждую подсистему с помощью активного пакета. Изобразите структурный граф, показывающий, какие компоненты подсистемы должны быть включены в эти пакеты: а) при применении метода, описанного в гл. 4; б) при использовании буферизующей задачи, рассмотренной в п. 4.8. Объясните, каким образом эта структура может быть использована в качестве универсального метода создания встроенных операционных систем для персональных рабочих станций.
Рассмотрите структурный граф системы DIALOGUE, приведенный на рис. 4.32. Изобразите аналогичный структурный граф, который показывал бы, как непродуманная внутренняя структура активного пакета, реализующего интерфейс с подсистемой обмена сообщениями, может приводить к тупику. (Указание. Определите, что произойдет, если при обращении к процедуре SEND-MESSAGE пакета вызывающий модуль вынужден будет ожидать выделения области памяти для передачи сообщения?)
Можно ли получить какие-либо дополнительные преимущества, спроектировав систему DIALOGUE заново не на основе модели с буферизующей задачей для механизма межзадачного взаимодействия, а с использованием задачи-курьера, как показано на рис. 4.32 ? Объясните свой ответ.
При альтернативном варианте структурного графа системы DIALOGUE (рис. 4.33) оказывается, что у задачи, осуществляющей обработку событий, нет никаких средств управления потоком поступающих сообщений. Разработайте нужный механизм регулирования информационного потока на основе обсуждений, проводившихся в гл. 3.
Разработайте внутреннюю логику задачи, осуществляющей обработку событий (см. рис. 4.33), включая построение структурного графа и написание программы на псевдокоде.
Начертите структурный граф, который служит основой для реализации графа потока данных, изображенного на рис. 4.34.
Глава 5
В случае использования механизма взаимодействий, при котором диспетчер выделяет абонентам задачи из пула, реализующего сервисные функции, как в случае системы BANK
(рис. 5.1), появляется возможность состязания между ними. Решение, представленное на рис. 5.1, свободно от указанного недостатка, но даже небольшая его модификация легко приводит к появлению этой возможности. Предполагается, что задача-диспетчер обладает двумя входами, к которым обращаются задачи-кассиры; через вход READY (ГОТОВ) они могут сообщить о состоянии готовности, а по входу WAIT-FOR-WORK (ОЖИДАНИЕ-РАБОТЫ) — ожидать поступления запросов. Вход WAIT-FOR-WORK должен быть защищен предохранителем. При такой структуре взаимодействия существует возможность возникновения состязаний между задачами, обращающимися к входу WAIT-FOR-WORK после вызова ими входа READY. Постройте структурный граф, иллюстрирующий взаимодействие между задачей-диспетчером и задачей-кассиром, и объясните механизм возникновения состязаний, используя временную диаграмму.
Запрограммируйте на псевдокоде процедуру REQUESTSERVICE, содержащуюся в банковском пакете (рис. 5.1, а).
Разработайте тело пакета MAILROOM, изображенного на рис. 5.7.
Разработайте тело пакета MAILROOM, изображенного на рис. 5.8.
Рассмотрите механизм управления потоком данных, описываемый структурными графами, представленными на рис. 5.11. Запрограммируйте на псевдокоде тела задач, реализующих как линейную, так и нелинейную структуры взаимодействий (рис. 5.11,6 и 5.11, г). Сравните оба метода. Объясните, почему подход, иллюстрируемый рис. 5.11, г, не обеспечивает реализации универсального механизма блокировки активизации задач. '
Напишите программу на псевдокоде, реализующую линейную структуру взаимодействия задач, для примера синхронизации операций чтения и записи, проиллюстрированного на рис. 5.16. Используйте подход, предложенный при обсуждении данного рисунка.
Объясните, каким образом использование линейной схемы ожидания в примере AGENT-POOL (АГЕНТСТВО) (рис. 5.17,6) может привести к возникновению состязания между задачами, в результате которого клиент получит неправильный номер обслуживающего его агента. Используйте временную диаграмму. Покажите, каким образом можно слегка модифицировать логику решения данной проблемы (см. рис. 5.17, а), чтобы вопрос возникновения состязаний между задачами стал несущественным.
Предполагается, что проблема возникновения состязаний между задачами (рис. 5.17,6) решена путем создания до-
полнительного входа задачи-диспетчера, благодаря чему задача-посредник имеет возможность проверять, была ли она уже выделена какому-либо клиенту. Задача-посредник может использовать этот вход только в том случае, если обращение к ней произошло до момента «прикрепления» к «клиенту». С какой новой трудностью сопряжено такое решение?
Рассмотрите проблемы проектирования коммуникационного пакета, который реализует концепцию узла надежности (рис. 5.23). Предполагается, что пакет может быть разделен на две части, одна из которых обеспечивает «экспорт» и «импорт» специальных запросных сообщений, адресованных входам задач, а другая — обмен сообщениями любого типа между узлами надежности. Выберите подходящую структуру интерфейса для модуля обмена сообщениями, а затем спроектируйте «экспортно-импортную часть» процедуры вызова входа. Эта часть пакета должна предусматривать упорядочение и согласование обращений к входам задач, принадлежащих одному и тому же узлу надежности, например, при помощи пула «задач-партнеров». Другой способ реализации может быть связан с условными вызовами входов, исходящими от задачи, которая управляет обращениями к входам (распорядитель вызовов). В любом случае в вашем проекте должна учитываться возможность того, что операторы приема, соответствующие нужным входам, будут защищены предохранителями.
Изучите описание родовых программных структур, приведенное в каком-либо руководстве по языку программирования Ада, и прокомментируйте возможность их включения в набор инструментальных средств языка Ада, используемых при проектировании систем в гл. 2—5.
Глава 6
Структура интерфейса между системами DIALOGUE и СОММ (рис. 6.9) основывается на канонической форме представления с использованием задач-курьеров для осуществления транспортировки данных в многоуровневых системах (рис. 6.3, г). При таком каноническом представлении задачи, реализующие функции каждого уровня, включены в некоторые пакеты. Однако задачи, реализующие систему DIALOGUE (рис. 6.9), оформлены по-другому. Покажите, как вся эта система может быть целиком включена в некоторый пакет с целью получения канонической структуры.
Покажите, каким образом можно изменить структуру интерфейса DIALOGUE/СОММ, представленную на рис. 6.9, для преобразования ее в каноническую структуру, ориентированную на использование буферизующих задач (см. рис. 6.4, в).
Спроектируйте заново управляющий пакет логического обмена кадрами данных, представленный на рис. 6.12, используя каноническую структуру с буферизующими задачами для многоуровневых систем (см. рис. 6.4,8).
Запрограммируйте на псевдокоде тело пакета F-PRO- TOCOL (рис. 6.14), применяя таблицы переходов конечных автоматов и следуя методу, использованному в гл. 4 при проектировании модуля дешифратора команд в системе LIFE.
Напишите программу на псевдокоде, описывающую внутреннюю логику задачи FS и основанную на идеях, иллюстрируемых рис. 6.13—6.15.
Покажите, каким образом можно модифицировать управляющий пакет физического обмена кадрами (рис 6.16), чтобы его можно было использовать в многоуровневой системе с канонической структурой на основе буферизующих задач.
Запрограммируйте на псевдокоде тело задачи, выполняющей обработку прерываний в рамках управляющего пакета физического обмена кадрами данных (рис. 6.16).
Предполагается, что в подсистеме СОММ тело пакета F (см. рис. 6.12) должно быть модифицировано без изменения синтаксиса и семантики его спецификации таким образом, чтобы он мог служить в качестве пакета ввода-вывода для устройства управления прямым доступом к памяти (УУПД) и реализовывал во всех деталях протокол обмена кадрами. Это автономное аппаратное устройство копирует кадры данных из буферных блоков, содержащихся в теле пакета F, в свои собственные буферы для последующей передачи; аналогичным образом оно копирует входящие кадры из собственных внутренних буферов в буферные блоки пакета F. По завершении копирования в обоих направлениях УУПД формирует два разных сигнала прерывания. Будем считать, что УУПД осуществляет все функции протокола обмена кадрами, так что пакет F только управляет передачей кадров в это устройство и приемом кадров из него, а также реализует информационный обмен с пакетом М. В результате функции пакета F становятся аналогичными функциям описанного в гл. 6 пакета Р, который больше не нужен. Постройте и подробно прокомментируйте граф информационных потоков и структурный граф, соответствующие телу нового пакета F, и объясните принцип его функционирования.
Рис. 6.17 иллюстрирует метод, при котором используется специальная задача для рассылки уведомлений об отказах, происходящих на уровне обмена кадрами, задачам вышестоящих уровней системы. Постройте структурные графы, показывающие, каким образом эта задача взаимодействует с верхними уровнями систем DIALOGUE и СОММ.
Используйте информационный граф, изображенный на рис. 6.19, в качестве базиса для повторного проектирования структурных графов подсистемы СОММ, основанных на использовании канонической модели многоуровневой системы с буферизующими задачами (см. рис. 6.4, в).
Глава 7
Возникновение состязаний между задачами может происходить различным образом. Пакет управления сетевым уровнем обмена с использованием протокола Х.25 (рис. 7.5) служит одним из примеров такого рода. В этом пакете существует возможность возникновения состязания между задачей, пытающейся обратиться к входу CONNECT (после того как задача DISPATCHER выделила ей номер канала), и задачей ROUTER-IN, вызывающей вход PUT для того, чтобы передать поступивший запрос на установление связи. Объясните причины появления эффекта состязания и возникающие при этом последствия, используя временную диаграмму. Какие механизмы восстановления информации неявно присутствуют на рис. 7.5?
Постройте упрощенный структурный граф, соответствующий пакету, который реализует сетевой уровень протокола Х.25 (рис. 7.5), для случая, когда этот пакет обеспечивает обмен по единственному виртуальному каналу. Исключите из рассмотрения все неиспользуемые элементы рис. 7.5. Обоснуйте ваш способ решения проблемы.
Перечертите заново соответствующие части структурного графа, описывающего пакет управления сетевым уровнем протокола X. 25 (рис. 7.5) для отображения возможности реа-, лизации несколько иного способа приема входящих вызовов; при поступлении пакета, содержащего запрос, из него извлекается адрес отправителя и передается абоненту, ожидающему по входу WAIT-FOR-CALL; абонент должен подтвердить прием этого запроса до того как будет послан пакет, содержащий ответ. Такой способ действий противоположен методу, иллюстрируемому рис. 7.5, где задача VCM немедленно отправляет пакет, содержащий подтверждение приема, и вынуждает абонента снять запрос на установление соединения, если оно нежелательно. Рассмотрите возможность изменения интерфейса пакета, выполняемых задачами функций и механизмов межзадачного взаимодействия с целью реализации указанного метода.
Какие изменения должны быть внесены в пакет, реализующий сетевой уровень протокола Х.25 (рис. 7.5), если задали УСМ не управляют функционированием фиксированных
виртуальных каналов обмена, а номера каналов выделяются им динамически? При таком подходе данная задача в различные моменты времени может управлять разными виртуальными каналами. Напомним, что поступающие пакеты с запросами на установление соединения, исходящие запросы, а также посылаемые подтверждения приема запросов содержат номер виртуального канала. В методе, иллюстрируемом рис. 7.5, номер виртуального канала, имеющийся в поступающем запросе, совершенно однозначно идентифицирует задачу VCM. Поэтому задача ROUTER-IN может использовать этот номер для пересылки запроса соответствующей задаче VCM. При использовании же метода динамического распределения номеров каналов подобная возможность отсутствует, поскольку в момент поступления такого пакета задаче ROUTER-IN неизвестно, какая из задач VCM будет управлять виртуальным соединением. В общем случае каждый раз, когда поступает пакет, содержащий запрос на установление соединения, или инициируется локальный вызов, свободной задаче VCM должен быть сообщен новый номер выделенного виртуального канала. Этот способ действий противоположен иллюстрируемому рис. 7.5, где свободная задача VCM сообщает диспетчеру номер обслуживаемого ею виртуального канала. (Пул задач-агентов, описанный в гл. 5, может послужить источником идей относительно способа осуществления динамического назначения номеров виртуальных каналов.)
Какие изменения в структуре, представленной на рис. 7.5, могут потребоваться в случае нескольких виртуальных каналов, если исключить буферизующую задачу?
Следуя принципам, изложенным в гл. 6 при построении пакета М, спроектируйте соответствующий интерфейсный пакет обмена, обеспечивающий передачу и прием сообщений на верхних уровнях системы (т. е. выше уровня пакета, реализующего протокол Х.25). Примите во внимание тот факт, что пакет, обеспечивающий функционирование сетевого уровня обмена, не включает механизма ожидания разрешения на передачу. Напомним, что проект, изложенный в гл. 6, предполагает наличие такого механизма.
Внесите изменения в структурный граф, изображенный на рис. 7.5, чтобы включить в него механизм ожидания разрешения информационного обмена, аналогичный тому, который имеется в различных пакетах, описанных в гл. 6.
Напишите на псевдокоде программу тела задачи-диспетчера, схематически изображенной на рис. 7.5.
Начертите структурный граф, показывающий, каким образом в интерфейсном пакете обмена сообщениями (п. 7.6)
может использоваться схема регистрации событий, приведенная на рис. 7.7.
Начертите отличный от схемы рис. 7.5 структурный граф, описывающий организацию тела пакета, реализующего протокол X. 25, с использованием только одной главной задачи, управляющей работой всех виртуальных каналов.
Начертите структурный граф для тела пакета, реализующего протокол Х.25 (рис. 7.5), с использованием двух задач: одной — для управления обменом запросами по всем виртуальным каналам, а другой — для управления обменом данными.
Напишите на псевдокоде программу тела задачи-диспетчера (см. рис. 7.5) для случая, когда задачи VCM создаются в динамическом режиме при поступлении запросов (как предлагается в подразд. 7.4.3).
Разработайте альтернативную структуру пакета, реализующего сетевой уровень протокола X. 25, используя в качестве отправной точки каноническую структуру взаимодействий посредством буферизующих задач (рис. 6.4, в). Пусть, как и прежде, каждая задача VCM управляет работой одного виртуального канала. Строгий подход заключается в том, чтобы создать одну буферизующую задачу для всех задач VCM; кроме того, необходимо иметь семейство входов, на которых эти задачи смогут ожидать выделения им номеров обслуживаемых каналов. Требуется ли использование диспетчера в этом случае, или его функции могут быть переданы буферизующей задаче? Сравните ваше проектное решение со схемой, представленной на рис. 7.5. Выгодно ли при таком подходе реализовывать каждую из функций пакета с помощью отдельной процедуры? Должен ли интерфейс пакета быть изменен таким образом, чтобы его спецификация содержала две процедуры — одну для передачи, а другую для приема данных, что схематически изображено на рис. 6.4, в?
Литература
Booh G. Describing Software Design in Ada, ACM SIGPLAN Notices, pp. 42—47, September, 1981.
Bowen B. A., Buhr R. J. A. The Logical Design of Multiple Microprocessor Systems, Englewood Cliffs, NJ, Prentice-Hall, Inc., 1980.
CCITT Recommendation X. 25.
Hansen Per Brinch, The Architecture of Concurrent Programming, Englewood Cliffs, NJ, Prentice-Hall, Inc., 1977.
IAPX-432 Object Primer, Intel Corporation, January, 1981.
Myers G. J. Reliable Software Through Composite Design. New York, Petro- celli/Charter, 1975. [Имеется перевод: Майерс Г. Надежность программного обеспечения. — М.; Мир, 1980]
Pyle I. C. The Ada Programming Language, Englewood Cliffs, NJ, Prentice-Hall, Inc., 1981. [Имеется перевод: Пайл Я. Ада — язык встроенных систем. — М.: Финансы и статистика, 1984.]
Reference Manual for the Ada Programming Language, Draft revised MIL — STD 1815, United States Department of Defence, July, 1982, ANSI/MII — STD—1815A, United States Department of Defence, January, 1983.
Wegner P. Programming with Ada: An Introduction by Means of Graduated Examples, Englewood Cliffs, NJ, Prentice-Hall, Inc., 1980. [Имеется перевод: Вегнер П. Программирование на языке Ада — М.: Мир, 1983.]
Yourdon Е., Constantine L. Structured Design, Englewood Cliffs, NJ, Prentice Hall, Inc., 1979,
Предметный указатель
Адресат (target) 76, 81
Альтернатива (alternative) 39,41, 289
Аномальное поведение модулей (aberrant behaviour) 208—212
Аппаратные средства (hardware) 18, 37
Буфер (buffer) 75
— дисплея (display buffer) 235
— кадров (frame buffer) 255
— обмена (communication buffer) 234
— опережающего ввода (type-ahead buffer) 167
Буферизация сообщений (message buffering) 235
Виртуальный канал (virtual circuit) 276—278, 287, 294
Вход (entry) 37, 56
Вызов входа (entry call) 39, 60
безусловный (unconditional entry call) 57
временной (timed entry call) 57, 291
■ условный (conditional entry
call) 57, 96
Гибкость (flexibility) 17, 221
Графическая нотация (pictorial notation) 26, 52, 54, 61
Граф потоков данных (data flow graph) 60, 121
— структурный (structure graph) 60, 61, 65, 101, 123
Дешифратор команд (command decoder) 146, 151, 155
— событий (event decoder) 146, 151, 155, 158, 162, 167, 168
Доступ (access) 55
■— динамический(dynamic access)
175
Драйвер (driver) 128
Жизненный цикл (life cycle) 8, 16—
112, 113
Заглушка (stub) 45, 46
Задача (task) 13, 35
■— буферизующая (buffer task) 37, 297
— вызываемая (accepting task) 56
— вызывающая (calling task) 56, 91
— обслуживающая 163
— подчиненная (slave task) 126, 163
— управляющая (master task) 126
— фоновая (background task) 163
Задача-адресат (target task) 84, 85—
98
Задача-диспетчер (dispatcher task) 280, 282, 287
Задача-курьер (transporter task) 83, 85, 96, 97, 155, 181
Задача-отправитель (sender task) 84, 85—89
Задача-планировщик (scheduler task) 79, 80, 192
Задача-посредник (third-party task) 106
Задача-потребитель (consumer task) 37—43, 181
Задача-производитель (producer task) 37, 39, 40
Задача-трассировщик (router task) 282, 283
Задержки no перегрузке (congestion delays) 60, 72, 81, 92
— скрытые (latency delays) 60, 73, 81
— структурные (structural delays) 60, 72, 81
Инструментальные средства (tools)'
66, 115
Интерактивное макетирование (interactive prototyping) 24
Интерфейс (interface) 28—30, 109, 113
— пользовательский (user interface) 113, 144
Информационный голод (starvation) 173, 187
Информационный потоковый граф (data flow graph) 121, 129, 145
Исключительные ситуации (exceptions) 29, 30, 51, 110, 205—208
Кадр данных (data frame) 224, 225, 235, 242, 256
— управляющий (control frame) 243 Канальный уровень обмена (link layer) 275, 280, 285
Кисс-принцип (KISS-principle) 10, 96, 111
Комментарий (comment) 108
Конечный автомат (finite state machine) 132, 152, 165, 168
Конфигурирование системы (system configuring) 173
Концептуальное представление (concept) 9, 19, 20, 26, 48, 109
Кредитный лимит (credit) 99, 239, 265
Кризис программного обеспечения (software crisis) 16, 22
Критическая секция (critical section) 58, 59
Логический кабель (logical cable) 20
—- уровень проектирования (logical design level) 13
— штекер (logical plug) 20, 63
Межзадачные связи (intertask communication) 29, 36, 45
Межмодульное взаимодействие (intermodule communication) 239
Методология проектирования (design methodology) 116
Механизм рандеву (rendezvous mechanism) 11, 29, 37, 45, 56, 63, 69, 74, 181
Микропроцессорный комплекс (microprocessor system) 114
Многоклавишная команда (multiple keystroke command) 161
Множественность ссылок (aliasing) 236, 247
Модель взаимодействия открытых систем (open system interconnection model) 297—299
— информационных потоков (data flow model) 26
Модуль логического обмена (logical management module) 225, 236—238, 249, 256
— физического обмена (physical management module) 225, 236—238, 249,
Модульная прочность (module strength) 221—223
,коммуникационная(communi-
cational strength) 222
.логическая (logical strength) 222
•процедурная (procedural strength) 222
— — функциональная (functional strength) 221, 225
— система (modular system) 9, 10, 14
Модульное сцепление (module coupling) 222, 223, 228, 230
Модульность (modularity) 17, 28, 99, 221
— конструктивная (implementation modularity) 221
— случайная (coincidental modularity) 222
— событийная (event modularity) 221, 223, 225
— функциональная (understandability modularity) 221, 225
Надежность (reliability) 17, 51, 52, 233
Накопитель событий (event pool) 168
Нестандартное планирование (out- of-order scheduling) 90, 91
Обмен сообщениями (communications) 235, 241
Объект (object) 15, 38, 110, 297
Окно (window) 242, 262, 289
Оператор выборочного ожидания (selective wait statement) 40, 41
— отбора (select statement) 59, 60, 190
— приема (accept statement) 60, 182, 196, 288
Определение типов (type definition) 23, 31
Организация прохождения задач (tasking) 28—30, 109
Отправитель (sender) 76, 81
Очередь на передачу (transmit queue) 262, 264
прием (receive queue) 264
Пакет (package) 15, 28—31, 35
— активный (active package) 75, 100—103
— вложенный (nested package) 158 — внутренний (internal package) 149, 168
— пассивный (passive package) 76, 77, 148
Пакетный ввод-вывод (packaged in- put/output) 29, 46—48
Параллельные процессы (concurrent processes) 11, 12, 14, 19
Пересылка сообщений (messaging) 165
Персональная ЭВМ (personal computer) 24
Порождение задач (creation of tasks) 173
Посредник (middle-man) 76
Поток информационных кадров (data frame flow) 240
Почтовый ящик (mailbox) 183
Предохранитель (guard) 41, 254, 284
Приватный тип (private type) 47
Принцип равноправия (equal-partner contention) 163, 237
Прозрачность (transparency) 221, 224
Протокол (protocol) 213, 218, 241— 245 249
- Х.25 (Х.25 protocol) 275-284, 297—299
Протокольный блок данных (protocol data unit) 241, 274, 276
Процедура (procedure) 15, 30, 185, 207
— ACCEPT — CALL 299
— CLEAR 284
— CONTROL 122
— DISPLAY 136
— GET 65
— OPEN 47
— PLACE —CALL 287
— POP 30—34, 77
— PUSH 30—34, 77
— PUT 100, 122
— RECEIVE 240, 241
— REQUEST—SERVICE 101, 175
— SEND — MSG 219, 240
— WAIT — FOR — CALL 284, 285
— WAIT —MSG 219
Пузырьковая диаграмма (bubble chart) 121
Пул буферов (buffer pool) 237, 247
— задач (task pool) 174
— сервисный (service pool) 103, 109
Равноправные модули (peer modules) 241, 244
Разрешение (credit) 99, 246
Разъем (plug) 18, 19
Регулирование потока сообщений (message flow control) 220, 237— 240
Реконфигурация (reconfiguration) 19, 20
Самоидентификация 180, 184
Свойство повторной входимости (reenterability) 77
Семейство входов (entry family) 91
Сервисный примитив (service primitive) 298
Сетевой уровень обмена (packet layer) 275, 280—286
Сеть передачи данных (communication network) 164
Система передачи сообщений (messaging system) 170
Скелет программы (program skeleton) 66—68
Спецификация интерфейса (interface specification) 15, 54
— пакета (package specification) 30, 31, 34, 108
— представлений (representation specification) 49
— функций системы (system functions specification) 113
Стадия планирования испытаний (test plan phase) 113
Статический доступ (static access) 175
Степень модульности (degree of modularity) 221
Столкновение запросов (call collision) 282, 283
Стратегия гпоектирования (design strategy) 116
«изнутри — к границам» (middle—out strategy) 116, 119
— ■— ориентированная на информационные потоки (data-flow-driven strategy) 116, 120
— ■— ориентированная на структуры данных (data-structure-driven strategy) 116, 120
«от границ—внутрь» (edges—in strategy) 116, 127
— — «сверху—вниз»(top—down
strategy) 116—119
«снизу — вверх» (bottom — up strategy) 116—119
Структура взаимодействий (interaction structure) 187—191, 204
Структурное проектирование (structured design) 11, 15, 26, 28, 173
Сценарий (script) 155
Тело задачи (task body) 178
— модуля (module body) 28
— пакета (package body) 31, 32, 46, 261
Тестовый журнал (test log) 211
Технические требования (requirements) 22, 23, 113
Тупиковая ситуация (deadlock) 93— 98, 193, 237—239
Уведомления о событиях (event notifications) 204
Узел надежности (reliability node) 214—216, 233, 273, 274
Указатель (pointer) НО
Управление запросами (call control) 287\
— логическим дисплеем (logical display management) 146, 148, 160 — потоком кадров (flow control of data frames) 242, 268 — физическим дисплеем '(physical display management) 146, 148
Управляющая структура (control structure) 296
Фаза анализа (analyze phase) 16
— описания (specify phase) 16
— поставки (deliver phase) 17
— проектирования (design phase) 16,
— реализации (implement phase) 17
■— эксплуатации и сопровождения (maintain phase) 17
Функциональная декомпозиция (functional decomposition) 116—120
■— иерархия (functional hierarchy)’ 119'
— клавиша (softkey) 163
Целевая система '(target system) 115
Черный ящик (black box) 15, 19, 20, 25, 28—31, 55'
Экологическая игра '(life game) 130— 133
Эскизное представление (doodling) 128
Монография
Р. Бар
ЯЗЫК АДА В ПРОЕКТИРОВАНИИ СИСТЕМ
Старший научный редактор Л. П. Якименко
Младший научный редактор М. Н. Стасюк
Художник В. А. Медников•
Художественный редактор Н. М. Иванов
Технический редактор Л. П. Бирюкова
Корректор С. А. Денисова
И Б № 6229
Сдано в набор 13.01.S7. Подписано к печати 21.08.87. Формат 60Х90г/1в. Бумага кн-журналь- ная. Печать высокая. Гарнитура литературная. Объем 10,00 бум. л. Усл. печ. л. 20,00. Усл. кр.-отт. 20,00. Уч.-нзд. л. 19,57. Изд. № 6/4871. Тираж 50 000 экз. Зак. 455. Цена 1 р. 70 к.
ИЗДАТЕЛЬСТВО «МИР», 129820, ГСП, Москва, И-110, 1-й Рижский пер., 2
Ленинградская типография № 2 головное предприятие ордена Трудового Красного Знамени Ленинградского объединения «Техническая книга» им. Евгении Соколовой Союз- полиграфпрома при Государственном комитете СССР по делам издательств, полиграфии и книжной торговли. 198052. г, Ленинград, Л-52, Измайловский проспект, 29.
Р. Бар
Язык Ада в проектировании систем
Перевод с английского канд. техн, наук О. С. Багатуровой, В. М. Храпкина, В. С. Явниловича
под редакцией
канд. техн, наук Е. К. Масловского
Scan Pirat
Москва «Мир» 1988
ББК 32.973 Б 25
УДК 681.32
Бар Р.
Язык Ада в проектировании систем: Пер. с англ. — М.: Б 25 Мир, 1988.— 320 с., ил.
В книге американского специалиста рассматривается методология разработки прикладных систем программного обеспечения с использованием средств алгоритмического языка Ада. Значительное внимание уделяется принципам формализованного описания проектируемых систем, обеспечивающим концептуальное единство всех их компонентов и возможность прямого преобразования системных представлений в Ада-программы. Изложение иллюстрируется множеством примеров, позволяющих легко освоить предлагаемую методологию.
Для разработчиков автоматизированных систем управления, системных и прикладных программистов, а также студентов соответствующих специальностей вузов. .
ББК 32.973ББК 32.973_ 2405000000-20
ББК 32.973
ББК 32.973
Ь 041(01)-88188 88’ 41 1
Редакция литературы по информатике и робототехнике
© 1984 by Prentice-Hall, Inc.
© перевод на русский язык, «Мир», 1988
Содержание
Предисловие редактора перевода . . . 5
Предисловие 8
Часть I
Концептуальные основы системного проектирования • ■ - . 15
Глава 1. Введение в проблему15
Обоснование предлагаемого подхода15
Проектирование системы и ее жизненныйцикл16
Некоторые замечания об аппаратных ипрограммных средствах 18
Сущность предлагаемого подхода25
Глава 2. Ада — язык системного проектирования28
Введение28
Нисходящий обзор характерных особенностей языка Ада, важных для разработчика систем . . . . 'ЗЭ
Критический анализ языка Ада49
Часть II
Введение в логическоепроектирование 53
Глава 3. Проектно-ориентированная методика наглядного описания систем 53
Вводныезамечания53
Средстванаглядногоописанияархитектуры систем ..... 54
Разработка набора компонентов стандартныхсистемных структур . 74
Связь структурных графов сАда-программами106
Заключение110
Глава 4. Введение в проектирование архитектуры системы (с примерами) 112
Введение112
Стратегия проектирования116
Эскизное представление потока данных: принципы поэтапной разработки проекта системы128
Пример разработки проекта: система, реализующая экологическую игру LIFE130
Пример разработки проекта: система FORMS, реализующая форматированный ввод и выводданных141
Пример проектирования системы DIALOGUE(ДИАЛОГ) . . .162
Заключение 171
Часть III
Анализ проблем логического проектирования172
Глава 5. Дополнительные сведения о языке Ада 172
Введение172
Вопросы динамического доступа и порождениязадач173
Содержание
Другие варианты структуры взаимодействия задач187
Механизм уведомления о событиях204
Контроль и обнаружение аномального поведения модулей . . . . 208
Компоновка систем . . . . ...216
Глава 6. Модульность, надежность и структурирование: практический пример.218
Введение218
Требование кподсистемеСОММ219
Модульность220
Надежность 233
Рабочее проектирование подсистемы СОММ .. 246
Заключительныезамечаниякпроекту267
Заключение274
Глава 7. Логическое проектирование многоуровневых систем: пример с применением протокола информационного обмена X. 25 . . . 275
Введение275
Основные особенности протокола X. 25 276
Разработка проекта многоуровневой системы с протоколом X. 25 . 279
Заключительные замечания к проекту290
Проектирование семиуровневой модели взаимодействия открытых систем 297
Заключение .. 299
Задания для самостоятельноговыполнения301
Литература313
Предметный указатель .. . . . 315