В данном разделе рассматриваются задачи, которые не относятся к области логического управления. В сфере прикладного программирования для персональных компьютеров системы со сложным поведением чаще всего являются событийными, автоматизированные объекты в них, как правило, пассивны. Что касается автоматных моделей, то удобнее всего использовать автоматы Мили или (реже) смешанные автоматы. Какие изменения в структуре алгоритма повлечет эта специфика? Поскольку используются другие автоматные модели, блок формирования выходных воздействий должен быть расположен по-другому. Команды объекта управления реализованы уже не аппаратно, а програмно, 2. как обыкновенные процедуры. Поэтому в блоке формирования выходных воздействий вместо присваивания значений выходным переменным следует поместить вызовы процедур, соответствующих тем выходным переменным, которые принимают значение «истина». Поскольку рассматриваемые автоматизированные объекты пассивны, изменилась и главная программа.
Рассмотрим схему алгоритма, описывающего один такт работы автомата Мили (рис. 2.32). Здесь блок формирования выходных воздействий находится за дешифратором входных воздействий и содержит вызовы определенных команд объекта управления Набор команд, которые должны быть вызваны, определяется значением функции выходов автомата для данного состояния и входного воздействия. Объединив этот алгоритм с алгоритмом такта работы автомата Мура из предыдущего раздела, получим алгоритм для смешанного автомата (рис. 2.33), в котором присутствуют два блока формирования выходных воздействий: до и после дешифратора входных воздействий. Главная программа изменилась гораздо сильнее. Как уже известно читателю, пассивная автоматная модель работает не постоянно (такт за тактом), а совершает очередной такт работы по инициативе внешней среды. Поэтому для таких моделей главная программа уже не является частью реализации автомата. Эта программа описывает функционирование внешней среды, и из нее в определенных местах может вызываться подпрограмма, реализующая такт работы автомата. В прикладных событийных системах функция главной программы, как правило, состоит в извлечении сообщений из очереди и передаче их соответствующим обработчикам. Однако это лишь вершина айсберга: прикладная программа работает под управлением операционной системы, которая берет на себя всю работу по приему событий от внешних устройств и передаче их программе. Поэтому само понятие главной программы в современных прикладных программных системах является относительным и неопределенным. Кроме того, при переходе к прикладному программированию событийных систем изменились и критерии оптимальности реализации автоматов. Изоморфизм программного кода графу переходов по-прежнему остается на первом месте, однако эффективность по времени и памяти для данного класса задач не столь критична. Напротив, большее значение приобретают гибкость и способность эволюционировать, адаптируясь к новым требованиям. Напомним, что в данном разделе обсуждаются вопросы реализации в контексте процедурного программирования. Объектно-ориентированный подход обладает более широким арсеналом методов и шаблонов для реализации автоматов, часть из них обсуждается далее в параграфе 3.3. А пока мы остаемся наедине с языком C и двумя способами реализации автоматов, перечисленными выше: с помощью таблиц и с помощью инструкций выбора. Существует ряд задач, в которых необходимо модифицировать автомат во время выполнения программы. Для таких случаев следует использовать реализацию автомата в виде таблицы. Однако опыт показывает, что такие задачи встречаются довольно редко. Поэтому наиболее употребительным остается шаблон реализации, описанный в предыдущем разделе: использование инструкции выбора в сочетании с инструкцией ветвления (тем более что такой способ упрощает изоморфное преобразование графа переходов в программный код).Шаблон реализации такта работы автомата изменился по сравнению с листингом 2.2 несущественно. Поскольку вместо автомата Мура теперь используется автомат Мили, то блок формирования выходного воздействия переместился внутрь инструкции ветвления. Кроме того, в этом блоке вместо присваивания значений выходным переменным теперь выполняются вызовы подпрограмм, соответствующих командам объекта управления. Более интересный вопрос — взаимодействие функции такта автомата с вызывающим контекстом, иначе говоря, передача автомату событий. Существует три основных варианта такого взаимодействия. События, как и входные переменные, являются 1. глобальными переменными программы или модуля программы, в котором находится автомат (отметим, что второй вариант менее вероятен, так как в отличие от входных переменных, которые являются локальными для автоматизированного объекта, события, как правило, предназначены для межмодульного взаимодействия). В том случае, если события исключительны (два события не могут произойти одновременно), для хранения текущего события достаточно ввести одну целочисленную переменную, значение которой в дешифраторе входных воздействий будет сравниваться с идентификаторами конкретных событий. Если же события в разрабатываемой системе не обладают свойством исключительности, для хранения множества текущих событий можно использовать битовый вектор. В таком случае представление событий ничем не отличается от представления входных переменных. Шаблон реализации функции такта автомата при этом способе представления событий отличается от описанного в листинге 2.2 только положением блока формирования выходных воздействий. События являются 2. аргументами функции такта автомата. Это проектное решение отражает различие между событиями и входными переменными: здесь автомат обрабатывает событие (или набор событий), в то время как значения входных переменных лишь при необходимости опрашиваются автоматом по его собственной инициативе. Кроме того, при реализации автомата вручную такое решение предотвращает программные ошибки, возможные при первом подходе: когда программист забывает установить переменную для хранения события перед вызовом такта автомата. Изменения в шаблоне реализации в этом случае незначительны и затрагивают только сигнатуру функции такта:void• A (int e), если события исключительны;void• A (bool[] e), если события неисключительны. Этот вариант реализации был предложен в работах Описание примера его использования на практике приведено в работе. Каждому событию сопоставляется отдельная 3. функция. Это решение подходит только для реализации исключительной модели событий (отметим, что эта модель является наиболее распространенной). Кроме того, оно отражает активную роль событий, тот факт, что именно возникновение события инициировало вызов автомата. К тому же это решение лучше всего согласовано с традиционной структурой программного модуля в событийных системах, где любая самостоятельная часть программы представляет собой множество обработчиков связанных по смыслу событий. Программа, построенная в соответствии с данным решением, уже не совсем изоморфна схеме алгоритма на рис. 2.32, где сначала дешифруется состояние, а затем входное воздействие. В этом случае сначала происходит ветвление по событиям, затем по состояниям и, наконец, по входным переменным. Это может показаться неоправданным усложнением. Однако в большинстве событийных систем внешняя среда с необходимостью производит дешифрацию события перед отправкой его автомату (хотя бы для того, чтобы понять, какому автомату следует его передать). В этом случае при использовании других решений дешифрация событий на каждом такте без всякой необходимости происходит два раза. Шаблон реализации функции такта для третьего способа взаимодействия автомата с внешней средой описан в листинге 2.6.Вариант реализации, близкий к описанному выше, был использован в работе. Рассмотрим все три предложенных варианта реализации взаимодействия автомата с внешней средой на примере часов с будильником — сущности со сложным поведением, управляющий автомат для которой был построен в разделе 2.1.1 В листинге 2.7 команды и запросы объекта управления часов с будильником в целях повышения модульности реализованы в виде отдельных функций, а не как часть реализации управляющего автомата В этом листинге используется первый из предложенных шаблонов (события описываются глобальными переменными).В листинге 2.8 представлена реализация управляющего автомата часов с будильником, использующая второй шаблон: события передаются автомату в качестве аргументов. Реализация объекта управления при этом не отличается от первого варианта и поэтому в листинге не приведена. Листинг 2.9 содержит реализацию управляющего автомата часов с будильником с помощью третьего шаблона: каждому событию сопоставляется отдельная функция.