One big problem with the UML transition sequence is that it requires executing actions associated with the transition after destroying the source state configuration but before creating the target state configuration. In the analogy between exit actions in state machines and destructors in OOP, this situation corresponds to executing a class method after partially destroying an object. Of course, such action is illegal in OOP. As it turns out, it is also particularly awkward to implement for state machines.
Executing actions associated with a transition is much more natural in the context of the source state--the same context in which the guard condition is evaluated. Only after the guard and the transition actions execute, the source state configuration is exited and the target state configuration is entered atomically. That way the state machine is observable only in a stable state configuration, either before or after the transition, but not in the middle.
Local versus external transitions
Before UML 2, the only transition semantics in use was the external transition, in which the main source of the transition is always exited and the main target of the transition is always entered. UML 2 preserved the "external transition" semantics for backward compatibility, but also introduced also a new kind of transition called local transition [8, Section 15.3.15].
For many transition topologies, external and local transitions are actually identical. However, a local transition doesn't cause exit from the main source state if the main target state is a substate of the main source. In addition, local state transition doesn't cause exit and reentry to the target state if the main target is a superstate of the main source state.
Figure 2.10 contrasts local (a) and external (b) transitions. In the top row, you see the case of the main source containing the target. The local transition does not cause exit from the source, while the external transition causes exit and re-entry to the source. In the bottom row of Figure 2.10, you see the case of the target containing the source. The local transition does not cause entry to the target, whereas the external transition causes exit and reentry to the target.
Figure 2.10: Local (a) versus external transitions (b). QP implements only the local transitions.
The HSM implementation described in the book Practical UML Statecharts in C/C++ supports exclusively the local state transition semantics.
Event deferral
Sometimes an event arrives at a particularly inconvenient time, when a state machine is in a state that cannot handle the event. In many cases, the nature of the event is such that it can be postponed (within limits) until the system enters another state, in which it is much better prepared to handle the original event.
UML state machines provide a special mechanism for deferring events in states. In every state, you can include a clause 'deferred / [event list]'. If an event in the current state's deferred event list occurs, the event will be saved (deferred) for future processing until a state is entered that does not list the event in its deferred event list. Upon entry to such state, the UML state machine will automatically recall any saved event(s) that are no longer deferred and process them as if they have just arrived.
NOTE: The HSM implementation described in the book this series is excerpted from--Practical UML Statecharts in C/C++--does not directly support the UML-style event deferral. However, the "Deferred Event" state pattern presented shows how to approximate this feature in a much less expensive way by explicitly deferring and recalling events.
UML statecharts and automatic code synthesis
UML statecharts provide sufficiently well-defined semantics for building executable state models. Indeed, several design automation tools on the market support various versions of statecharts (see the sidebar "Design Automation Tools Supporting Statecharts"). The commercially available design automation tools typically not only automatically generate code from statecharts but also enable debugging and testing of the state models at the graphical level.7
But what does automatic code generation really mean? And more important, what kind of code is actually generated by such statechart-based tools?
Many people understand automatic code synthesis as the generation of a program to solve a problem from a statement of the problem specification. Statechart-based tools cannot provide this because a statechart is just a higher-level (mostly visual) solution rather than the statement of the problem.
As far as the automatically generated code is concerned, the statechart-based tools can autonomously generate only so-called "housekeeping code".7 The modeler explicitly must provide all the application-specific code, such as action and guard expressions, to the tool. The role of housekeeping code is to "glue" the various action and guard expressions together to ensure proper state machine execution in accordance with the statechart semantics. For example, synthesized code typically handles event queuing, event dispatching, guard evaluation, or transition chain execution (including exit and entry of appropriate states). Almost universally, the tools also encompass some kind of real-time framework that integrates tightly with the underlying operating system.
Design automation tools supporting statecharts
Some of the computer-aided software-engineering (CASE) tools with support for statecharts currently available on the market are:
Telelogic Statemate, www.telelogic.com (the tool originally developed by I-Logix, Inc. acquired by Telelogic in 2006, which in turn is in the process of being acquired by IBM) .
Telelogic Rhapsody, www.telelogic.com.
Rational Suite Development Studio Real-Time, Rational Software Corporation, www.ibm.com/software/rational (Rational was acquired by IBM in 2006)
ARTiSAN Studio, ARTiSAN Software Tools, Ltd., www.artisansw.com.
Stateflow, The Mathworks, www.mathworks.com
VisualSTATE, IAR Systems, www.iar.com
|