UML state machine
A UML state machine is a behavioral specification within the Unified Modeling Language (UML) that models the dynamic behavior of a system, object, or classifier through a finite set of states, transitions triggered by events, and associated actions or activities.[1] It represents discrete behavior as a graph where vertices denote states (situations in which an invariant condition holds for the modeled entity) and edges denote transitions (changes from one state to another, often conditioned by guards and effects).[1] UML distinguishes two primary kinds: behavioral state machines, which specify the complete life cycle of a reactive object including responses to external or internal events, and protocol state machines, which focus on the valid sequences of messages or operations (usage protocols) without detailing internal actions.[1] Originating as an object-oriented extension of David Harel's statecharts formalism, UML state machines were introduced in UML 1.x and refined in subsequent versions by the Object Management Group (OMG) to support complex, concurrent behaviors through features like composite states, orthogonal regions, and pseudostates (e.g., initial, final, history, and junction pseudostates).[1] Every state machine includes a top-level region that organizes its hierarchy, enabling nested structures for modularity and reuse via submachines or state refinements.[1] These diagrams are particularly useful in software engineering for designing reactive systems, such as embedded software, user interfaces, and protocols, by visualizing how entities evolve over time in response to stimuli while ensuring completeness and consistency in behavioral models.[1] The formalism emphasizes executability, with precise semantics defined in the UML superstructure to allow simulation, verification, and code generation from state machine models.[2]Introduction
Definition and Purpose
A UML state machine is a graphical notation in the Unified Modeling Language (UML) for specifying the behavior of entities, such as classes, objects, or components, in response to events by defining their states, transitions between those states, and associated actions.[3] This formalism enables modelers to represent discrete, event-driven behaviors where the system responds differently depending on its current state, providing a structured way to visualize and document dynamic system aspects.[4] The primary purpose of UML state machines is to model reactive systems, object lifecycles, and state sequences in software design, particularly in domains requiring precise control over timing and responses, such as embedded systems and real-time applications.[5] They facilitate the analysis of complex interactions by focusing on how entities evolve over time in response to stimuli, aiding in requirements specification, verification, and implementation of reliable behaviors without delving into algorithmic details.[3] UML distinguishes between two types of state machines: behavioral state machines, which describe all possible sequences of states an entity may enter, including internal actions and reactions to events; and protocol state machines, which specify the permissible sequences of operation calls and messages on an entity's interface, emphasizing legal usage protocols without internal behavioral details.[6] Behavioral state machines are suited for modeling complete lifecycles, while protocol state machines focus on external constraints and preconditions for interactions.[3] For example, a behavioral state machine can model a traffic light controller with states including red, green, and yellow, where transitions occur via time-based events to ensure safe sequencing.[7] Similarly, an order processing system might employ states like pending, approved, shipped, and delivered, with transitions triggered by events such as payment receipt or logistics updates, illustrating how state machines capture business workflows.[8]Historical Context and Evolution
The concept of state machines in UML traces its origins to the 1980s, when David Harel introduced statecharts as a visual formalism to model complex reactive systems, extending traditional finite state machines (FSMs) with hierarchical nesting and orthogonality to mitigate issues like state explosion in concurrent behaviors.[9] Harel's work, formalized in his 1987 paper, addressed key limitations of classical FSMs by allowing states to contain substates and enabling independent concurrent regions, which facilitated the modeling of systems with multiple orthogonal components without combinatorial growth in state count.[9] This innovation was implemented in the Statemate tool, developed by i-Logix in collaboration with Harel, which provided executable semantics for statecharts and influenced subsequent modeling practices in software engineering.[10] In the early 1990s, object-oriented modeling approaches further shaped the evolution of state-based notations. James Rumbaugh's Object Modeling Technique (OMT), introduced in 1991, incorporated state transition diagrams as part of its dynamic model to capture the life history of objects through events and state changes, bridging behavioral modeling with structural object-oriented design.[11] Similarly, Bran Selic's Real-time Object-Oriented Modeling (ROOM) in the mid-1990s extended statecharts for real-time systems, emphasizing capsules with concurrent state machines and message passing, which addressed synchronization challenges in distributed environments.[12] These methodologies, including influences from Grady Booch's work on object lifecycles, converged to inform UML's behavioral diagrams. UML integrated statechart concepts upon its standardization by the Object Management Group (OMG) in November 1997 with UML 1.1, where statechart diagrams—later renamed state machines—were introduced to specify object behaviors in response to events, drawing directly from Harel's formalism and OMT's dynamic elements.[13] A major advancement occurred with UML 2.0 in July 2005, which enhanced state machines with refined support for concurrency through orthogonal regions and deeper hierarchical nesting, including the introduction of local transitions, allowing more scalable models of complex, multi-threaded systems while preserving the run-to-completion semantics. Further minor refinements in UML 2.5.1, released in December 2017, clarified aspects of the semantics, such as redefinable vertices in state machines.[14] These evolutions, guided by OMG's revision task forces, progressively addressed FSM limitations by embedding orthogonality and hierarchy as core features, enabling UML state machines to model sophisticated reactive systems effectively.[14]Core Elements
States and Pseudostates
In UML state machines, states represent the fundamental units that capture the situations in which an object or system exhibits specific behaviors or conditions. A state is a vertex that models a situation during which some invariant condition holds, and the object performs certain activities or waits for events. Simple states, also known as atomic or basic states, are indivisible units without substates, serving as the leaf nodes in the state hierarchy. They depict moments when the system is stable and ready to respond to incoming events, often including internal behaviors such as entry actions (executed upon entering the state), do activities (ongoing behaviors), and exit actions (executed upon leaving). In notation, simple states are depicted as rounded rectangles containing the state name, with optional compartments for internal transitions or activities below. For instance, a simple state named "Idle" might represent a device waiting for user input, with an entry action to initialize resources.[4] Composite states extend simple states by enclosing one or more regions that contain substates, enabling hierarchical modeling to manage complexity, though the detailed nesting mechanics are addressed elsewhere. They are visually represented as larger rounded rectangles with internal boundaries for regions, which can be sequential (single-threaded) or orthogonal (concurrent via dashed lines). A composite state like "Processing Order" might encompass substates for validation and fulfillment, allowing the system to enter a specific substate upon activation.[4] Pseudostates are transient vertices that do not represent actual states but serve as markers or connectors within the state machine to control flow and initialization. Unlike regular states, pseudostates cannot hold invariants or execute activities and are not instantiable; they facilitate entry, exit, branching, and history tracking. The UML specification defines several kinds, each with distinct notation and semantics. The initial pseudostate denotes the default starting point of a region or the entire state machine, from which exactly one outgoing transition fires without a trigger or guard to enter the initial substate. It is graphically shown as a small solid black circle. In a login process example, an initial pseudostate might transition to a "Enter Credentials" simple state upon state machine activation.[4] The final pseudostate indicates the completion of a region or the state machine, signaling termination with no further processing in that scope; multiple finals can exist in orthogonal regions. It appears as a circle enclosing a smaller solid black circle, often called a bullseye. Continuing the login example, a final pseudostate could mark successful authentication, ending the process.[4] History pseudostates allow resumption of a composite state at a previously active substate configuration after interruption. The shallow history (denoted by a circle with an "H" inside) restores only the immediate substate, while the deep history (circle with "H*" ) restores the full nested configuration. These are useful for scenarios like pausing and resuming workflows.[4] Choice pseudostates enable dynamic conditional branching based on guards evaluated at runtime, modeled as a diamond shape with one incoming and multiple outgoing transitions. They support exclusive or (XOR) decisions without explicit events.[4] Junction pseudostates facilitate static merging of incoming transitions or splitting into outgoing ones based on guards, represented as a small black circle with short cross lines; they are useful for converging paths without dynamic evaluation.[4] Entry and exit point pseudostates provide designated portals for entering or leaving composite states, especially in orthogonal regions. An entry point is a small circle on the composite state's boundary, and an exit point is a circle with an "X" inside, allowing transitions to connect externally while encapsulating internals.[4] Fork pseudostates split a single incoming transition into multiple concurrent transitions targeting orthogonal regions, initiating parallel execution paths; they are represented as a short thick horizontal bar with one incoming arrow and multiple outgoing arrows.[4] Join pseudostates synchronize multiple incoming transitions from orthogonal regions into a single outgoing transition, waiting for all incoming paths to complete before firing; they are also depicted as a short thick horizontal bar.[4] Terminate pseudostates explicitly terminate the execution of the entire state machine, preventing further event processing; they are shown as a circle enclosing an X.[4]Events
In UML state machines, events represent detectable occurrences or conditions that can trigger transitions between states, serving as the primary stimuli for behavioral changes in a modeled system. These events are processed according to the run-to-completion semantics, where an event is dispatched from an event pool associated with the state machine's context classifier and evaluated against applicable transitions. The event pool acts as a queue for incoming event occurrences, ensuring that events are handled one at a time without interference during processing. UML defines four main types of events, each suited to different kinds of stimuli. Call events occur when an operation of the context classifier is invoked synchronously, such as a method call that blocks the sender until completion; their notation in transition triggers is simply the operation name followed by parameters if any, e.g.,processPayment(amount). Signal events, in contrast, are triggered by the asynchronous receipt of a signal defined in the classifier's receptions, allowing non-blocking communication like messages in distributed systems; they are denoted as the signal name, e.g., coinInserted(). Time events are relative or absolute timing specifications that fire after a duration or at a specific point, notated as after(duration) for relative time (e.g., after(30 seconds)) or at(timeExpression) for absolute; these are useful for modeling timeouts or scheduled behaviors. Change events detect when a Boolean expression evaluating the state of the system becomes true, such as a variable threshold being crossed, and are written as when([condition](/page/Condition)), e.g., when(inventory < 5).[15]
The role of events in state machine behavior centers on their dispatch and consumption: upon occurrence, an event instance enters the event pool of the owning instance or behavioral feature, from which it is dequeued and matched against transition triggers in the current state configuration. If no transition fires, the event is discarded unless deferred in the current state; otherwise, it initiates the transition selection process, potentially leading to state changes. This queuing mechanism supports concurrent event handling in complex systems while maintaining deterministic execution. Events may carry parameters providing contextual data, such as values or objects, which can be accessed in guards or actions.[4]
A representative example illustrates the distinction between call and signal events in a vending machine state machine. A selectItem(productId) call event might synchronously invoke an operation to process a user's button press, immediately validating and deducting from the balance if sufficient funds exist, reflecting a direct, blocking interaction. In contrast, a coinInserted(amount) signal event arrives asynchronously from a coin acceptor hardware interrupt, queuing independently without halting other operations, allowing the machine to handle multiple insertions fluidly before processing. Time events like after(60 seconds) could trigger an idle state from a waiting state if no selection occurs, while a change event such as when(balance >= price) enables the transition to dispensing upon accumulation of sufficient asynchronous signals.[7]
Transitions and Guards
In UML state machines, transitions represent directed relationships that connect a source state to a target state, specifying how the system responds to events by changing its state. A transition is triggered by an event and may include an optional guard condition and an effect, collectively notated as event [guard] / action. This triplet allows precise modeling of dynamic behavior, where the event initiates the potential change, the guard evaluates whether the transition is permissible, and the action denotes any immediate behavior executed during the transition. Guard conditions are Boolean expressions that must evaluate to true for a transition to fire upon occurrence of its triggering event; they are dynamically assessed based on the current context, including extended state variables and event parameters. Guards are typically expressed using the Object Constraint Language (OCL) or simpler logical expressions, ensuring they reference only elements accessible at evaluation time, such as state attributes or event data. To prevent nondeterministic behavior, guards on outgoing transitions from the same source state for the same event must be mutually exclusive, meaning at most one can be true at any given time. UML distinguishes between external and local transitions based on their scope within hierarchical structures. An external transition connects states potentially across different composite boundaries, triggering full exit actions from the source state (and its enclosing composites) and entry actions into the target state (and its enclosing composites). In contrast, a local transition operates solely within a composite state between its substates, executing only the substate exit and entry actions without affecting the enclosing composite's behaviors; further details on their effects appear in the section on local and external transitions. Both types use the same arrow notation but differ in graphical rendering: external transitions show a solid arrow with a triangle head, while local transitions may appear as a bent arrow staying within the composite boundary. For illustration, consider an ATM system's authentication flow. From an "Idle" state, a card insertion event triggers transitions to a "Card Inserted" substate. Subsequent PIN entry might then lead to parallel transitions: one to "Authenticated" if [pinValid] (a guard checking the entered PIN against stored credentials), or to "PIN Error" if [pinInvalid] and retry attempts remain. This ensures the machine only proceeds to transaction states under verified conditions, with the guards [pinValid] and [pinInvalid] being mutually exclusive.[16]Behaviors and Actions
Actions and Activities
In UML state machines, actions represent atomic, executable behaviors that specify instantaneous responses to events or state changes, such as method invocations or variable assignments, ensuring they complete without interruption.[3] These behaviors are modeled as opaque expressions or references to operations and form the basic units of execution within the state machine's dynamics.[3] Activities, in contrast, denote extended, ongoing behaviors that may involve complex workflows, often realized through references to UML activity diagrams for detailed specification.[3] Unlike actions, activities can run concurrently and for indeterminate durations, capturing processes that persist while a state remains active.[3] They provide a mechanism to decompose intricate operations beyond simple atomic steps. Actions and activities attach to various elements in a state machine, including transitions as effects that execute upon firing (after guards but before entering the target state) and states as do-activities for concurrent execution during state residence.[3] Entry and exit actions on states offer additional attachment points for behaviors triggered by state ingress or egress, though their precise invocation sequences are addressed separately.[3] For instance, a simple action on a transition might log an event occurrence, such as recording a user input in a system log via a method call likelogEvent("inputReceived").[4] In comparison, an activity attached as a do-activity in an "Order Processing" state could reference an activity diagram modeling the full payment processing workflow, including validation, charging, and confirmation steps in an e-commerce application.[3]
Entry, Exit, and Internal Transitions
In UML state machines, entry actions represent behaviors that are automatically executed upon entering a state, irrespective of the incoming transition. These actions are particularly useful for performing initialization tasks, such as setting initial values for local variables or allocating resources required during the state's lifetime. As defined in the UML specification, entry actions are specified within the internal activities compartment of a state and notated using the keyword "entry" followed by a slash and the action expression, for example, "entry / initializeBuffer()". Exit actions, conversely, are behaviors triggered automatically when leaving a state, regardless of the outgoing transition. They serve purposes like cleanup operations, such as releasing resources, logging state completion, or saving persistent data to ensure proper termination. The UML notation for exit actions mirrors that of entry actions but uses the "exit" keyword, placed in the same internal activities compartment, as in "exit / cleanupResources()". According to the specification, exit actions execute after any ongoing do-activities in the state have completed, maintaining the integrity of the state's ongoing processes. Internal transitions enable a state to respond to specific events without exiting or re-entering the state, thus avoiding the invocation of entry or exit actions. This mechanism is essential for handling minor events, such as status updates or error notifications, that do not warrant a full state change. In the UML semantics, internal transitions have higher priority than outgoing transitions from the same state; if both are applicable to an event, the internal transition takes precedence. They are notated either as self-transitions (arrows looping back to the state) or listed in a dedicated internal transitions compartment with the event trigger, optional guard, and effect, for example, "error / logError(message)" without a target vertex.[4] The execution semantics for these elements follow a strict order within the run-to-completion model of UML state machines: upon state entry, the entry action executes first, followed by any do-activity (a continuous behavior during the state's residence); upon exit, the do-activity completes before the exit action runs. This sequencing ensures that initialization precedes ongoing state behavior and cleanup follows it, preventing resource leaks or inconsistent states. For instance, in a "Processing Order" state, an internal transition might handle a "lowPriorityAlert" event by simply incrementing a counter and logging it, without disrupting the processing do-activity.[4]Extended States and Variables
In UML state machines, extended states augment the basic discrete states by incorporating quantitative information through extended state variables, which capture the history and context of the system's behavior. These variables represent the program's memory and allow the state machine to model dynamic conditions without requiring an exponential increase in the number of discrete states. For instance, instead of defining separate states for every possible count in a retry mechanism, a single variable can track the number of attempts, enabling the machine to respond based on its current value. This concept, rooted in the UML formalism, combines the qualitative aspect of the current state with the quantitative values of these variables to form the complete extended state.[12] Variables in UML state machines can be attributes of the owning classifier (such as an object or class) or local to the state machine instance, and they are updated through actions triggered by events or transitions. These updates occur during state entry, exit, or internal processing, allowing the variables to influence future behavior. The role of such variables is to introduce memory into what would otherwise be a memoryless finite state machine, facilitating the modeling of real-world systems where past events affect present decisions, such as incrementing a counter after each failed authentication attempt. By maintaining these variables, UML state machines can handle complex scenarios efficiently, as demonstrated in examples like a keyboard state machine where akey_count variable decrements with each keystroke until reaching zero, triggering a failure state.[12][17]
A practical example is a network connection state machine with an extended state including a timeout variable that measures elapsed time since the last activity. If an event occurs while the machine is in a "Connected" state, an action might reset the timeout to zero; otherwise, a guard condition like [timeout > 30] on a transition to "Disconnected" evaluates the variable to decide whether to terminate the connection. This approach ensures that the state machine remains concise while incorporating time-sensitive or accumulative logic, directly supporting the use of variables in guards and actions as defined in the UML standard.[12][18]
Execution Semantics
Run-to-Completion Model
The run-to-completion (RTC) model constitutes the core execution semantics for UML state machines, stipulating that the processing of each event occurs in a discrete, atomic step that fully completes before the state machine can respond to any subsequent event. In this model, a step initiates upon the dispatch of an event to the state machine, encompassing the evaluation of transitions, execution of associated actions, and stabilization into a new configuration, after which the machine enters an idle state awaiting the next queued event.[12] Central to the RTC model are principles of non-preemption and event queuing: during a step, no incoming events can interrupt the ongoing execution, with all pending events instead accumulated in an event pool for sequential processing once the current step concludes.[5] This ensures that actions—such as entry or exit behaviors triggered within the step—are completed without interference, maintaining the integrity of the state machine's configuration throughout.[12] The implications of the RTC model include guaranteed deterministic behavior in single-threaded implementations, as it precludes race conditions or nondeterministic interleaving that could arise from concurrent event handling within a single state machine.[5] By enforcing atomicity, it simplifies verification and debugging, though it may introduce latency in systems where long-running actions delay responsiveness to time-sensitive events.[12] For instance, in an event-driven system modeling a user interface, the RTC model ensures that a complete response to a button press event—including state transitions and associated computations—is processed atomically before queuing and handling a subsequent timer expiration event, thereby avoiding partial updates or inconsistent states.[5]Transition Execution Sequence
In UML state machines, the execution of a transition adheres to a strict sequence to maintain behavioral consistency, especially in hierarchical configurations. Upon firing a transition, the system first invokes the exit behaviors of the source state, proceeding outward through its containing composite states up to the least common ancestor (LCA) with the target state; this ensures that all relevant inner-to-outer exits are completed before any effect is triggered. Next, the transition's own effect—such as an action or activity—is executed. Finally, the entry behaviors of the target state are invoked, starting from the LCA and proceeding inward to the target, thereby reestablishing the nested state configuration. This ordered propagation through the hierarchy is foundational to UML's operational semantics, as defined in the standard.[19] When multiple transitions are eligible for the same event, conflict resolution prioritizes the highest-priority one, typically the transition originating from the innermost state or one explicitly assigned higher priority via model annotations; lower-priority transitions are deferred or ignored until the selected one completes, preventing nondeterministic behavior. This priority mechanism applies dynamically during event processing, ensuring that deeper, more specific reactions take precedence over shallower ones.[20] In nested structures, the transition sequence interrupts and terminates any ongoing do-activities within the traversed states to avoid interference; this ensures isolation of the atomic transition step without preserving interrupted behaviors across the transition.[19] For instance, consider a hierarchical state machine modeling a vehicle's control system, where the current state is "Driving > Cruising > SpeedMaintain" and an event triggers a transition to "Parked > Secured." The sequence executes as follows: exit "SpeedMaintain" (e.g., stop throttle adjustment), exit "Cruising," exit "Driving" (e.g., log departure), perform the transition effect (e.g., apply brakes), enter "Parked" (e.g., initialize parking mode), and enter "Secured" (e.g., lock systems). This example illustrates how the hierarchy dictates the outward-then-inward flow, with do-activities like continuous speed monitoring interrupted and terminated during the process.[21] This detailed sequence operates within the enclosing run-to-completion model, where the entire process is atomic relative to external events.Local and External Transitions
In UML state machines, external transitions represent the standard and default type of transition, where firing the transition results in a complete exit from the source vertex—including all its enclosing composite states up to the least common superstate with the target—and a subsequent entry into the target vertex and its enclosing states, executing all relevant exit and entry actions along the path. This full traversal ensures that the state machine properly handles changes across the hierarchy, making external transitions suitable for shifts between distinct high-level states. Local transitions, by contrast, are confined to the interior of a single composite state, connecting a source vertex to a target vertex both nested within that composite. When triggered, a local transition executes without causing an exit from or entry to the enclosing composite state itself, thereby avoiding the execution of the composite's exit or entry actions and limiting effects to the involved subvertices. Unlike self-transitions (which are classified as internal), local transitions require distinct source and target vertices and can only occur within composite states. In diagrams, local transitions are visually indicated by arrows that remain entirely within the composite state's boundary, without crossing it, distinguishing them from external transitions that may span across boundaries. The distinction between local and external transitions enables more granular control over state machine behavior in hierarchical models. Local transitions promote efficiency by allowing rapid changes among substates—such as switching between "insert mode" and "select mode" within an "editing" composite state in a user interface application—without reinitializing the parent composite or disrupting its ongoing context. External transitions, however, are essential for broader state changes that necessitate full hierarchy traversal, such as exiting the "editing" composite entirely to enter a "saving" state. UML 2.5 introduced clarifications to the semantics of local transitions to address prior ambiguities in hierarchy traversal and action execution, ensuring that their confinement to substructures yields more predictable and consistent outcomes in complex designs. These refinements, carried forward into UML 2.5.1 with minor adjustments, emphasize that local transitions do not propagate effects beyond the composite, aligning with the run-to-completion model while supporting modular state refinements.[19]Advanced Structures
Hierarchical Nesting
In UML state machines, hierarchical nesting is achieved through composite states, which serve as containers for sub-machines and enable the organization of complex behaviors into structured hierarchies. A composite state is defined by the propertyisComposite = true and contains one or more regions, each of which can hold nested states and transitions, allowing for direct substates (immediately contained) or transitive nesting (deeper levels). This structure permits the encapsulation of related behaviors within a single enclosing state, reducing the overall complexity of the diagram by grouping elements logically.[3]
Upon entry into a composite state, execution begins with initial transitions from an initial pseudostate, typically represented as a filled black circle, to one or more substates within its regions. Each region must have an initial vertex connected by a default transition, which is taken implicitly unless overridden by an explicit incoming transition targeting a specific substate; absence of an initial pseudostate may render the model ill-formed. These initial transitions ensure a well-defined starting point for the sub-machine, facilitating sequential activation of nested behaviors. Pseudostates like the initial vertex play a crucial role in this entry mechanism.[3]
The primary benefits of hierarchical nesting include enhanced modularity and the promotion of shared behaviors across levels. By decomposing large state machines into reusable composite units, nesting supports modular design, making models easier to maintain and extend without redundancy. Enclosing states can define shared entry, exit, and doActivity behaviors that apply to all substates, or common transitions that substates inherit, thereby enabling efficient reuse of logic and reducing duplication in specifications.[3]
Event propagation in nested structures ensures robust handling by allowing unhandled events in a substate to bubble up to the enclosing composite state. If an event does not trigger a transition or is deferred within the inner state, it is propagated outward for potential processing at higher levels, preventing loss of events while maintaining hierarchical control. Events deferred in a state remain queued until the state is exited or the event is explicitly handled.[3]
For example, consider a state machine modeling a video game where a top-level "Playing" composite state contains substates such as "LevelInProgress," "Paused," and "GameOver." Upon entering "Playing," an initial transition from the region's initial pseudostate activates "LevelInProgress," inheriting shared entry actions like loading game assets from the composite. An unhandled "pause" event in "LevelInProgress" propagates to "Playing," triggering a transition to "Paused," which reuses the enclosing state's doActivity for background music continuity. This nesting modularizes the play mode, allowing sub-modes to share common pause/resume logic without repetition.[3]
Orthogonal Regions
Orthogonal regions in UML state machines enable the modeling of concurrent, independent behaviors within a single composite state, allowing multiple sub-machines to operate in parallel without direct interference unless explicitly synchronized. A composite state is orthogonal when it contains two or more regions, visually represented by dashed lines dividing the state into separate compartments.[3] Each region functions as a self-contained state machine fragment, possessing its own set of states, transitions, and pseudostates, including dedicated initial and final pseudostates to manage entry and completion independently.[3] This structure supports the representation of systems where parallel activities, such as processing user inputs and handling network communications, can evolve simultaneously.[3] Synchronization between orthogonal regions occurs through specific pseudostates that coordinate transitions across regions. A fork pseudostate splits an incoming transition into multiple concurrent transitions, each targeting a vertex in a different region, thereby initiating parallel execution without evaluating guards sequentially.[3] Conversely, a join pseudostate merges outgoing transitions from multiple regions into a single transition, firing only when all incoming transitions from the specified regions have completed and their guards evaluate to true.[3] These mechanisms ensure controlled interaction in concurrent scenarios, such as synchronizing the completion of data processing in one region with status updates in another before proceeding to a subsequent state.[3] In terms of execution semantics, orthogonal regions operate under the run-to-completion model extended for concurrency, where each region processes events independently during a state machine step. Events are broadcast to all active regions upon occurrence, potentially triggering at most one transition per bottom-level region per event, while entry and exit actions of the enclosing composite state execute only once regardless of the number of regions.[3] A composite state remains active as long as at least one of its regions is active, and the overall state machine completes an execution step only after all regions have finished their run-to-completion processing for the current event.[3] The completion of all regions in an orthogonal state can implicitly trigger an outgoing transition from the composite state, signaling the end of concurrent activities.[3] A practical example of orthogonal regions is modeling a networked device, such as a smart thermostat, where one region handles user interface interactions (e.g., button presses transitioning between display modes) and another manages communication protocols (e.g., sending status updates over Wi-Fi), with a fork pseudostate initiating both upon device activation and a join synchronizing them before entering a maintenance state.[3] This approach, often nested within hierarchical states for added structure, facilitates the design of complex, reactive systems exhibiting true parallelism.[3]Event Deferral and History States
In UML state machines, event deferral is a mechanism that allows certain events to be temporarily postponed rather than immediately discarded when they occur in a state where they cannot be handled. When an event is deferred in a state, it is placed into the event pool of the state machine and retained until the machine enters a state where the event is no longer deferred, at which point it becomes eligible for processing according to the run-to-completion semantics.[3] This feature is particularly useful for managing out-of-order or low-priority events, such as deferring a low-priority signal in an idle state until a more appropriate active state is reached, ensuring that critical events are not lost while avoiding unnecessary state changes.[3] The notation for deferred events involves specifying a list of deferrable events within a dedicated compartment of the state symbol, using the syntaxevent1, event2, ... / defer.[3] Deferred events are associated with the state via the deferrableTrigger property, and conflicts in deferral across orthogonal regions are resolved non-deterministically, though this is handled within the broader execution model.[3] Upon entry to a state that does not defer the event, it is automatically recalled from the pool and evaluated as if it had just occurred, maintaining the original order in the event queue.[3]
History states in UML state machines are pseudostates that enable the resumption of a previous substate configuration within a composite state after an interruption, providing a form of state memory. There are two variants: shallow history and deep history. A shallow history pseudostate remembers only the most recent active direct substate (at the immediate level) of the enclosing composite state or region; upon re-entry, the state machine transitions to that substate, or to the default initial substate if no history exists.[3] In contrast, a deep history pseudostate captures the complete active configuration, including all nested substates recursively throughout the hierarchy; re-entry restores the entire remembered subtree, again defaulting to the initial configuration if none is recorded.[3]
Graphically, history pseudostates are denoted by a small open circle containing an "H" for shallow history or "H*" for deep history, placed within the boundary of the composite state it applies to, with an outgoing transition to the remembered substates or defaults.[3] This mechanism is valuable for modeling interruptible processes, such as a workflow in a phone call state machine where, after transitioning to a "hold" state and returning, the history state resumes the exact prior subconfiguration (e.g., "connected" with active participants) rather than resetting to an initial setup.[3] At most one history pseudostate of each type is permitted per region of a composite state to avoid ambiguity in restoration.[3]