Имеет значение порядок выполнения условного перехода. Пусть имеется состояние S, из которого при событии E совершается переход T с условием C и действием A. Переход T осуществляется в такой последовательности:
• Происходит событие E.
• Проверяется условие C.
• Если C удовлетворено, то выполняется переход T и действие A.
Это означает, что если условие C не выполнено, то переход не может быть осуществлен до тех пор, пока событие E не произойдет еще раз и условие C не будет проверено еще раз. Побочные эффекты при вычислении условия или выполнении действия, назначенного на выход, не могут отменить переход. Например, предположим, что произошло событие E, условие C выполнилось, но действие A, выполняемое при выходе из состояния S, изменило ситуацию так, что условие C перестало выполняться: переход T все равно состоялся.
Мы можем использовать еще и следующий синтаксис:
• in Cooling - выражение для текущего состояния.
Здесь используется имя состояния (которое может быть квалифицированным). Выражение истинно тогда и только тогда, когда система находится в указанном состоянии. Такие условия особенно полезны, когда некоторому внешнему состоянию нужно запустить переход по условию, связанному с некоторым вложенным состоянием.
Можно использовать в условии и выражение, налагающее ограничения по времени:
• timeout (Heating, 30) - выражение ограничения по времени.
Это условие выполняется, если система более 30 секунд находилась в состоянии Heating и остается в нем в момент проверки. Этот тип условия употребляется в системах реального времени для "переходов без события", так как защищает систему от зависания на долгое время в одном состоянии. Это выражение можно использовать для указания нижней границы времени нахождения в данном состоянии. Если приложить временное ограничение к каждому переходу с событием, выводящим из данного состояния, это будет равнозначно требованию, что система находится в каждом состоянии как минимум время, указанное в ограничении [Харел предложил "обобщенную завитушку" для обозначения двухсторонних границ по времени, но мы не будем обсуждать здесь его обобщения, так как условия исчерпания времени достаточно выразительны].
Что случится, если некое событие произойдет, а перейти в другое состояние нельзя либо потому, что не существует перехода для данного события, либо не выполняется условие перехода? По умолчанию это надо считать ошибкой: игнорирование событий обычно является признаком неполного анализа задачи. Вообще, для каждого состояния нужно документировать события, которые оно намеренно игнорирует.
Вложенные состояния. Возможность вложения состояний друг в друга придает глубину диаграммам переходов; эта ключевая особенность карт состояний Харела предотвращает комбинаторный взрыв в структуре состояний и переходов, который часто случается в сложных системах.
На рис. 5-21 показаны внутренние детали состояния Cooling, то есть вложенные в него состояния; для простоты мы опустили все его действия, включая действия при входе и выходе.
Объемлющие состояния, такие, как Cooling, называются суперсостояниями, а вложенные, такие, как Running, - подсостояниями. Вложенность может достигать любой глубины, то есть подсостояние может быть суперсостоянием для вложенных состояний более низкого уровня. Данное суперсостояние Cooling содержит три подсостояния. Семантика вложенности подразумевает отношение xor (исключающее или) для вложенных состояний: если система находится в состоянии Cooling (охлаждение), то она находится ровно в одном из подсостояний Startup (начальное), Ready (готовность) или Running (выполнение).
Чтобы проще ориентироваться в диаграмме переходов с вложенными состоя-ниями мы можем увеличить или уменьшить ее масштаб относительно выбранного состояния. При уменьшении вложенные состояния исчезают, а при увеличении проявляются. Переходы в скрытые на диаграмме подсостояния и выходы из них показываются стрелкой с черточкой, как переход в состояние Ready на рисунке [Если быть точными, то переходы Too hot и Ok относительно состояния Cooling также должны быть показаны на рис. 5-21 с черточкой, так как это переходы между подсостояниями].
Переходам между состояниями разрешено начинаться и кончаться на любом уровне. Рассмотрим различные формы переходов:
• Переход между одноуровневыми состояниями (такой, как из Failure в Idle или из Ready в Running) - простейшая форма перехода; его семантика описана в предыдущем разделе.
• Можно совершить переход непосредственно в подсостояние (как из Idle в Startup), или непосредственно из подсостояния (как из Running в Idle), или одновременно и то, и другое.