Topics
Prev Next

Example: Fork and Join

Fork pseudostates split an incoming Transition into two or more Transitions terminating in Vertices in orthogonal Regions of a Composite State. The Transitions outgoing from a Fork pseudostate cannot have a guard or a trigger, and the effect behaviors of the individual outgoing Transitions are, at least conceptually, executed concurrently with each other.

Join pseudostates are a common target Vertex for two or more Transitions originating from Vertices in different orthogonal Regions. Join pseudostates perform a synchronization function, whereby all incoming Transitions have to complete before execution can continue through an outgoing Transition.

In this example, we demonstrate the behavior of a StateMachine with Fork and Join pseudostates.

Modeling StateMachine

Context of StateMachine

  • Create a Class element named MyClass, which serves as the context of a StateMachine
  • Right-click on MyClass in the Project Browser and select the 'Add | StateMachine' option

StateMachine

  • Add an Initial Node, a Fork, a State named State1, a Join, and a Final to the diagram
  • Enlarge State1, right-click on it on the diagram and select the 'Advanced | Define Concurrent Substates | Define' option and define RegionA and RegionB
  • In RegionA, define StateA1, transition to StateA2, triggered by event X
  • In RegionB, define StateB1, transition to StateB2, triggered by event Y
  • Draw other transitions: Initial to Fork; Fork to StateA1 and StateB1; StateA2 and StateB2  to Join; Join to Final

Simulation

Artifact

Enterprise Architect supports C, C++, C#, Java and JavaScript; we will use JavaScript in this example because we don't need to install a compiler (for the other languages, either Visual Studio or JDK are required).

  • From the Diagram Toolbox select the 'Artifacts' page and drag the Executable StateMachine icon onto the diagram to create an Artifact; name it ForkNJoinSimulation and set its 'Language' field to 'JavaScript'
  • Ctrl+Drag MyClass from the Project Browser and drop it on the ForkNJoinSimulation Artifact as a Property; give it the name myClass

Code Generation

  • Right-click on ForkNJoinSimulation and select the 'Code Engineering | Executable StateMachine | Generate, Build and Run' option
  • Specify a directory for the generated source code

Note: The contents of this directory will be cleared before generation; make sure you point to a directory that exists only for StateMachine simulation purposes.

Run Simulation

When simulation is started, State1, StateA1 and StateB1 are active and the StateMachine is waiting for events.

Select the 'Simulate > Dynamic Simulation > Triggers' ribbon option to display the Simulation Events window.

On Trigger event X, StateA1 will exit and enter StateA2; after the entry and doActivity behavior has run, the completion events of StateA2 are dispatched and recalled. Then the transition from StateA2 to the Join pseudostate is enabled and traversed.

Note: Join must wait for all incoming Transitions to complete before execution can continue through an outgoing Transition. Since the branch from RegionB is not complete (because StateB1 is still active and waiting for triggers) the transition from Join to Final will not be executed at this moment.

On Trigger event Y, StateB1 will exit and enter StateB2; after the entry and doActivity behavior has run, completion events of StateB2 are dispatched and recalled. Then the transition from StateB2 to the Join pseudostate is enabled and traversed. This satisfies the criteria of all the incoming transitions of Join having completed, so the transition from Join to Final is executed. Simulation has ended.

Tips: You can view the execution trace sequence from the Simulation window (Simulate > Dynamic Simulation > Simulator > Open Simulation Window).

        myClass[MyClass].Initial_82285__TO__fork_82286_82286_61745 Effect

        myClass[MyClass].StateMachine_State1 ENTRY

        myClass[MyClass].StateMachine_State1 DO

        myClass[MyClass].fork_82286_82286__TO__StateA1_57125 Effect

        myClass[MyClass].StateMachine_State1_StateA1 ENTRY

        myClass[MyClass].StateMachine_State1_StateA1 DO

        myClass[MyClass].fork_82286_82286__TO__StateB1_57126 Effect

        myClass[MyClass].StateMachine_State1_StateB1 ENTRY

        myClass[MyClass].StateMachine_State1_StateB1 DO

        Trigger X

        myClass[MyClass].StateMachine_State1_StateA1 EXIT

        myClass[MyClass].StateA1__TO__StateA2_57135 Effect

        myClass[MyClass].StateMachine_State1_StateA2 ENTRY

        myClass[MyClass].StateMachine_State1_StateA2 DO

        myClass[MyClass].StateMachine_State1_StateA2 EXIT

        myClass[MyClass].StateA2__TO__join_82287_82287_57134 Effect

        Trigger Y

        myClass[MyClass].StateMachine_State1_StateB1 EXIT

        myClass[MyClass].StateB1__TO__StateB2_57133 Effect

        myClass[MyClass].StateMachine_State1_StateB2 ENTRY

        myClass[MyClass].StateMachine_State1_StateB2 DO

        myClass[MyClass].StateMachine_State1_StateB2 EXIT

        myClass[MyClass].StateB2__TO__join_82287_82287_57132 Effect

        myClass[MyClass].StateMachine_State1 EXIT

        myClass[MyClass].join_82287_82287__TO__Final_105754_57130 Effect