1 <!DOCTYPE html PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN">
5 <meta http-equiv=
"Content-Language" content=
"en-us">
6 <meta http-equiv=
"Content-Type" content=
"text/html; charset=us-ascii">
7 <meta name=
"GENERATOR" content=
"Microsoft FrontPage 6.0">
8 <meta name=
"ProgId" content=
"FrontPage.Editor.Document">
9 <link rel=
"stylesheet" type=
"text/css" href=
"../../../boost.css">
11 <title>The Boost Statechart Library - Tutorial
</title>
14 <body link=
"#0000FF" vlink=
"#800080">
15 <table border=
"0" cellpadding=
"7" cellspacing=
"0" width=
"100%" summary=
18 <td valign=
"top" width=
"300">
19 <h3><a href=
"../../../index.htm"><img alt=
"C++ Boost" src=
20 "../../../boost.png" border=
"0" width=
"277" height=
"86"></a></h3>
24 <h1 align=
"center">The Boost Statechart Library
</h1>
26 <h2 align=
"center">Tutorial
</h2>
32 <p>A Japanese translation of an earlier version of this tutorial can be
34 "http://prdownloads.sourceforge.jp/jyugem/7127/fsm-tutorial-jp.pdf">http://prdownloads.sourceforge.jp/jyugem/
7127/fsm-tutorial-jp.pdf
</a>.
35 Kindly contributed by Mitsuo Fukasawa.
</p>
39 <dl class=
"page-index">
40 <dt><a href=
"#Introduction">Introduction
</a></dt>
42 <dd><a href=
"#HowToReadThisTutorial">How to read this tutorial
</a></dd>
44 <dt><a href=
"#HelloWorld">Hello World!
</a></dt>
46 <dt><a href=
"#BasicTopicsAStopWatch">Basic topics: A stop watch
</a></dt>
48 <dd><a href=
"#DefiningStatesAndEvents">Defining states and
51 <dd><a href=
"#AddingReactions">Adding reactions
</a></dd>
53 <dd><a href=
"#StateLocalStorage">State-local storage
</a></dd>
55 <dd><a href=
"#GettingStateInformationOutOfTheMachine">Getting state
56 information out of the machine
</a></dd>
58 <dt><a href=
"#IntermediateTopicsADigitalCamera">Intermediate topics: A
59 digital camera
</a></dt>
62 "#SpreadingAStateMachineOverMultipleTranslationUnits">Spreading a state
63 machine over multiple translation units
</a></dd>
65 <dd><a href=
"#DeferringEvents">Deferring events
</a></dd>
67 <dd><a href=
"#Guards">Guards
</a></dd>
69 <dd><a href=
"#InStateReactions">In-state reactions
</a></dd>
71 <dd><a href=
"#TransitionActions">Transition actions
</a></dd>
73 <dt><a href=
"#AdvancedTopics">Advanced topics
</a></dt>
75 <dd><a href=
"#SpecifyingMultipleReactionsForAState">Specifying multiple
76 reactions for a state
</a></dd>
78 <dd><a href=
"#PostingEvents">Posting events
</a></dd>
80 <dd><a href=
"#History">History
</a></dd>
82 <dd><a href=
"#OrthogonalStates">Orthogonal states
</a></dd>
84 <dd><a href=
"#StateQueries">State queries
</a></dd>
86 <dd><a href=
"#StateTypeInformation">State type information
</a></dd>
88 <dd><a href=
"#ExceptionHandling">Exception handling
</a></dd>
90 <dd><a href=
"#SubmachinesAndParameterizedStates">Submachines
&
91 Parametrized States
</a></dd>
93 <dd><a href=
"#AsynchronousStateMachines">Asynchronous state
98 <h2><a name=
"Introduction" id=
"Introduction">Introduction
</a></h2>
100 <p>The Boost Statechart library is a framework that allows you to quickly
101 transform a UML statechart into executable C++ code,
<b>without
</b> needing
102 to use a code generator. Thanks to support for almost all UML features the
103 transformation is straight-forward and the resulting C++ code is a nearly
104 redundancy-free textual description of the statechart.
</p>
106 <h3><a name=
"HowToReadThisTutorial" id=
"HowToReadThisTutorial">How to read
107 this tutorial
</a></h3>
109 <p>This tutorial was designed to be read linearly. First time users should
110 start reading right at the beginning and stop as soon as they know enough
111 for the task at hand. Specifically:
</p>
114 <li>Small and simple machines with just a handful of states can be
115 implemented reasonably well by using the features described under
116 <a href=
"#BasicTopicsAStopWatch">Basic topics: A stop watch
</a></li>
118 <li>For larger machines with up to roughly a dozen states the features
119 described under
<a href=
"#IntermediateTopicsADigitalCamera">Intermediate
120 topics: A digital camera
</a> are often helpful
</li>
122 <li>Finally, users wanting to create even more complex machines and
123 project architects evaluating Boost.Statechart should also read the
124 <a href=
"#AdvancedTopics">Advanced topics
</a> section at the end.
125 Moreover, reading the
<a href=
126 "rationale.html#Limitations">Limitations
</a> section in the Rationale is
127 strongly suggested
</li>
130 <h2><a name=
"HelloWorld" id=
"HelloWorld">Hello World!
</a></h2>
132 <p>We will use the simplest possible program to make our first steps. The
135 <p><img alt=
"HelloWorld" src=
"HelloWorld.gif" border=
"0" width=
"379"
138 <p>... is implemented with the following code:
</p>
140 #include
<boost/statechart/state_machine.hpp
>
141 #include
<boost/statechart/simple_state.hpp
>
142 #include
<iostream
>
144 namespace sc = boost::statechart;
146 // We are declaring all types as
<code>struct
</code>s only to avoid having to
147 // type
<code>public
</code>. If you don't mind doing so, you can just as well
148 // use
<code>class.
</code>
150 // We need to forward-declare the initial state because it can
151 // only be defined at a point where the state machine is
155 // Boost.Statechart makes heavy use of the curiously recurring
156 // template pattern. The deriving class must always be passed as
157 // the first parameter to all base class templates.
159 // The state machine must be informed which state it has to
160 // enter when the machine is initiated. That's why Greeting is
161 // passed as the second template parameter.
162 struct Machine : sc::state_machine
< Machine, Greeting
> {};
164 // For each state we need to define which state machine it
165 // belongs to and where it is located in the statechart. Both is
166 // specified with Context argument that is passed to
167 // simple_state
<>. For a flat state machine as we have it here,
168 // the context is always the state machine. Consequently,
169 // Machine must be passed as the second template parameter to
170 // Greeting's base (the Context parameter is explained in more
171 // detail in the next example).
172 struct Greeting : sc::simple_state
< Greeting, Machine
>
174 // Whenever the state machine enters a state, it creates an
175 // object of the corresponding state class. The object is then
176 // kept alive as long as the machine remains in the state.
177 // Finally, the object is destroyed when the state machine
178 // exits the state. Therefore, a state entry action can be
179 // defined by adding a constructor and a state exit action can
180 // be defined by adding a destructor.
181 Greeting() { std::cout
<< "Hello World!\n"; } // entry
182 ~Greeting() { std::cout
<< "Bye Bye World!\n"; } // exit
188 // The machine is not yet running after construction. We start
189 // it by calling initiate(). This triggers the construction of
190 // the initial state Greeting
191 myMachine.initiate();
192 // When we leave main(), myMachine is destructed what leads to
193 // the destruction of all currently active states.
198 <p>This prints
<code>Hello World!
</code> and
<code>Bye Bye World!
</code>
201 <h2><a name=
"BasicTopicsAStopWatch" id=
"BasicTopicsAStopWatch">Basic
202 topics: A stop watch
</a></h2>
204 <p>Next we will model a simple mechanical stop watch with a state machine.
205 Such watches typically have two buttons:
</p>
213 <p>And two states:
</p>
216 <li>Stopped: The hands reside in the position where they were last
220 <li>Pressing the reset button moves the hands back to the
0 position.
221 The watch remains in the Stopped state
</li>
223 <li>Pressing the start/stop button leads to a transition to the
228 <li>Running: The hands of the watch are in motion and continually show
232 <li>Pressing the reset button moves the hands back to the
0 position
233 and leads to a transition to the Stopped state
</li>
235 <li>Pressing the start/stop button leads to a transition to the
241 <p>Here is one way to specify this in UML:
</p>
243 <p><img alt=
"StopWatch" src=
"StopWatch.gif" border=
"0" width=
"560" height=
246 <h3><a name=
"DefiningStatesAndEvents" id=
"DefiningStatesAndEvents">Defining
247 states and events
</a></h3>
249 <p>The two buttons are modeled by two events. Moreover, we also define the
250 necessary states and the initial state.
<b>The following code is our
251 starting point, subsequent code snippets must be inserted
</b>:
</p>
253 #include
<boost/statechart/event.hpp
>
254 #include
<boost/statechart/state_machine.hpp
>
255 #include
<boost/statechart/simple_state.hpp
>
257 namespace sc = boost::statechart;
259 struct EvStartStop : sc::event
< EvStartStop
> {};
260 struct EvReset : sc::event
< EvReset
> {};
263 struct StopWatch : sc::state_machine
< StopWatch, Active
> {};
267 // The simple_state class template accepts up to four parameters:
268 // - The third parameter specifies the inner initial state, if
269 // there is one. Here, only Active has inner states, which is
270 // why it needs to pass its inner initial state Stopped to its
272 // - The fourth parameter specifies whether and what kind of
275 // Active is the outermost state and therefore needs to pass the
276 // state machine class it belongs to
277 struct Active : sc::simple_state
<
278 Active, StopWatch, Stopped
> {};
280 // Stopped and Running both specify Active as their Context,
281 // which makes them nested inside Active
282 struct Running : sc::simple_state
< Running, Active
> {};
283 struct Stopped : sc::simple_state
< Stopped, Active
> {};
285 // Because the context of a state must be a complete type (i.e.
286 // not forward declared), a machine must be defined from
287 //
"outside to inside". That is, we always start with the state
288 // machine, followed by outermost states, followed by the direct
289 // inner states of outermost states and so on. We can do so in a
290 // breadth-first or depth-first way or employ a mixture of the
301 <p>This compiles but doesn't do anything observable yet.
</p>
303 <h3><a name=
"AddingReactions" id=
"AddingReactions">Adding
306 <p>For the moment we will use only one type of reaction: transitions. We
307 <b>insert
</b> the bold parts of the following code:
</p>
309 <b>#include
<boost/statechart/transition.hpp
>
314 struct Active : sc::simple_state
< Active, StopWatch, Stopped
>
316 <b>typedef sc::transition
< EvReset, Active
> reactions;
</b>
319 struct Running : sc::simple_state
< Running, Active
>
321 <b>typedef sc::transition
< EvStartStop, Stopped
> reactions;
</b>
324 struct Stopped : sc::simple_state
< Stopped, Active
>
326 <b>typedef sc::transition
< EvStartStop, Running
> reactions;
</b>
329 // A state can define an arbitrary number of reactions. That's
330 // why we have to put them into an mpl::list
<> as soon as there
331 // is more than one of them
333 "#SpecifyingMultipleReactionsForAState">Specifying multiple reactions for a state
</a>).
339 <b>myWatch.process_event( EvStartStop() );
340 </b> <b>myWatch.process_event( EvStartStop() );
341 </b> <b>myWatch.process_event( EvStartStop() );
342 </b> <b>myWatch.process_event( EvReset() );
347 <p>Now we have all the states and all the transitions in place and a number
348 of events are also sent to the stop watch. The machine dutifully makes the
349 transitions we would expect, but no actions are executed yet.
</p>
351 <h3><a name=
"StateLocalStorage" id=
"StateLocalStorage">State-local
354 <p>Next we'll make the stop watch actually measure time. Depending on the
355 state the stop watch is in, we need different variables:
</p>
358 <li>Stopped: One variable holding the elapsed time
</li>
360 <li>Running: One variable holding the elapsed time
<b>and
</b> one
361 variable storing the point in time at which the watch was last
365 <p>We observe that the elapsed time variable is needed no matter what state
366 the machine is in. Moreover, this variable should be reset to
0 when we
367 send an
<code>EvReset
</code> event to the machine. The other variable is
368 only needed while the machine is in the Running state. It should be set to
369 the current time of the system clock whenever we enter the Running state.
370 Upon exit we simply subtract the start time from the current system clock
371 time and add the result to the elapsed time.
</p>
373 <b>#include
<ctime
>
378 struct Active : sc::simple_state
< Active, StopWatch, Stopped
>
381 typedef sc::transition
< EvReset, Active
> reactions;
383 <b>Active() : elapsedTime_(
0.0 ) {}
384 </b> <b>double ElapsedTime() const { return elapsedTime_; }
385 </b> <b>double
& ElapsedTime() { return elapsedTime_; }
387 </b> <b>double elapsedTime_;
390 struct Running : sc::simple_state
< Running, Active
>
393 typedef sc::transition
< EvStartStop, Stopped
> reactions;
395 <b>Running() : startTime_( std::time(
0 ) ) {}
398 // Similar to when a derived class object accesses its
399 // base class portion, context
<>() is used to gain
400 // access to the direct or indirect context of a state.
401 // This can either be a direct or indirect outer state
402 // or the state machine itself
403 // (e.g. here: context
< StopWatch
>()).
404 <b>context
< Active
>().ElapsedTime() +=
405 </b> <b>std::difftime( std::time(
0 ), startTime_ );
408 </b> <b>std::time_t startTime_;
414 <p>The machine now measures the time, but we cannot yet retrieve it from
415 the main program.
</p>
417 <p>At this point, the advantages of state-local storage (which is still a
418 relatively little-known feature) may not yet have become apparent. The FAQ
419 item
"<a href="faq.html#StateLocalStorage
">What's so cool about state-local
420 storage?</a>" tries to explain them in more detail by comparing this
421 StopWatch with one that does not make use of state-local storage.
</p>
423 <h3><a name=
"GettingStateInformationOutOfTheMachine" id=
424 "GettingStateInformationOutOfTheMachine">Getting state information out of
427 <p>To retrieve the measured time, we need a mechanism to get state
428 information out of the machine. With our current machine design there are
429 two ways to do that. For the sake of simplicity we use the less efficient
430 one:
<code>state_cast
<>()
</code> (StopWatch2.cpp shows the slightly
431 more complex alternative). As the name suggests, the semantics are very
432 similar to the ones of
<code>dynamic_cast
</code>. For example, when we call
433 <code>myWatch.state_cast
< const Stopped
& >()
</code> <b>and
</b>
434 the machine is currently in the Stopped state, we get a reference to the
435 <code>Stopped
</code> state. Otherwise
<code>std::bad_cast
</code> is thrown.
436 We can use this functionality to implement a
<code>StopWatch
</code> member
437 function that returns the elapsed time. However, rather than ask the
438 machine in which state it is and then switch to different calculations for
439 the elapsed time, we put the calculation into the Stopped and Running
440 states and use an interface to retrieve the elapsed time:
</p>
442 <b>#include
<iostream
>
446 <b>struct IElapsedTime
448 </b> <b>virtual double ElapsedTime() const =
0;
452 struct StopWatch : sc::state_machine
< StopWatch, Active
>
454 <b>double ElapsedTime() const
456 </b> <b>return state_cast
< const IElapsedTime
& >().ElapsedTime();
462 struct Running :
<b>IElapsedTime,
</b>
463 sc::simple_state
< Running, Active
>
466 typedef sc::transition
< EvStartStop, Stopped
> reactions;
468 Running() : startTime_( std::time(
0 ) ) {}
471 <b>context
< Active
>().ElapsedTime() = ElapsedTime();
474 </b> <b>virtual double ElapsedTime() const
476 </b> <b>return context
< Active
>().ElapsedTime() +
477 </b> <b>std::difftime( std::time(
0 ), startTime_ );
480 std::time_t startTime_;
483 struct Stopped :
<b>IElapsedTime,
</b>
484 sc::simple_state
< Stopped, Active
>
486 typedef sc::transition
< EvStartStop, Running
> reactions;
488 <b>virtual double ElapsedTime() const
490 </b> <b>return context
< Active
>().ElapsedTime();
498 <b>std::cout
<< myWatch.ElapsedTime()
<< "\n";
499 </b> myWatch.process_event( EvStartStop() );
500 <b>std::cout
<< myWatch.ElapsedTime()
<< "\n";
501 </b> myWatch.process_event( EvStartStop() );
502 <b>std::cout
<< myWatch.ElapsedTime()
<< "\n";
503 </b> myWatch.process_event( EvStartStop() );
504 <b>std::cout
<< myWatch.ElapsedTime()
<< "\n";
505 </b> myWatch.process_event( EvReset() );
506 <b>std::cout
<< myWatch.ElapsedTime()
<< "\n";
511 <p>To actually see time being measured, you might want to single-step
512 through the statements in
<code>main()
</code>. The StopWatch example
513 extends this program to an interactive console application.
</p>
515 <h2><a name=
"IntermediateTopicsADigitalCamera" id=
516 "IntermediateTopicsADigitalCamera">Intermediate topics: A digital
519 <p>So far so good. However, the approach presented above has a few
523 <li>Bad scalability: As soon as the compiler reaches the point where
524 <code>state_machine::initiate()
</code> is called, a number of template
525 instantiations take place, which can only succeed if the full declaration
526 of each and every state of the machine is known. That is, the whole
527 layout of a state machine must be implemented in one single translation
528 unit (actions can be compiled separately, but this is of no importance
529 here). For bigger (and more real-world) state machines, this leads to the
530 following limitations:
533 <li>At some point compilers reach their internal template
534 instantiation limits and give up. This can happen even for
535 moderately-sized machines. For example, in debug mode one popular
536 compiler refused to compile earlier versions of the BitMachine
537 example for anything above
3 bits. This means that the compiler
538 reached its limits somewhere between
8 states,
24 transitions and
16
539 states,
64 transitions
</li>
541 <li>Multiple programmers can hardly work on the same state machine
542 simultaneously because every layout change will inevitably lead to a
543 recompilation of the whole state machine
</li>
547 <li>Maximum one reaction per event: According to UML a state can have
548 multiple reactions triggered by the same event. This makes sense when all
549 reactions have mutually exclusive guards. The interface we used above
550 only allows for at most one unguarded reaction for each event. Moreover,
551 the UML concepts junction and choice point are not directly
555 <p>All these limitations can be overcome with custom reactions.
<b>Warning:
556 It is easy to abuse custom reactions up to the point of invoking undefined
557 behavior. Please study the documentation before employing them!
</b></p>
559 <h3><a name=
"SpreadingAStateMachineOverMultipleTranslationUnits" id=
560 "SpreadingAStateMachineOverMultipleTranslationUnits">Spreading a state
561 machine over multiple translation units
</a></h3>
563 <p>Let's say your company would like to develop a digital camera. The
564 camera has the following controls:
</p>
567 <li>Shutter button, which can be half-pressed and fully-pressed. The
568 associated events are
<code>EvShutterHalf
</code>,
569 <code>EvShutterFull
</code> and
<code>EvShutterReleased
</code></li>
571 <li>Config button, represented by the
<code>EvConfig
</code> event
</li>
573 <li>A number of other buttons that are not of interest here
</li>
576 <p>One use case for the camera says that the photographer can half-press
577 the shutter
<b>anywhere
</b> in the configuration mode and the camera will
578 immediately go into shooting mode. The following statechart is one way to
579 achieve this behavior:
</p>
581 <p><img alt=
"Camera" src=
"Camera.gif" border=
"0" width=
"544" height=
584 <p>The Configuring and Shooting states will contain numerous nested states
585 while the Idle state is relatively simple. It was therefore decided to
586 build two teams. One will implement the shooting mode while the other will
587 implement the configuration mode. The two teams have already agreed on the
588 interface that the shooting team will use to retrieve the configuration
589 settings. We would like to ensure that the two teams can work with the
590 least possible interference. So, we put the two states in their own
591 translation units so that machine layout changes within the Configuring
592 state will never lead to a recompilation of the inner workings of the
593 Shooting state and vice versa.
</p>
595 <p><b>Unlike in the previous example, the excerpts presented here often
596 outline different options to achieve the same effect. That's why the code
597 is often not equal to the Camera example code.
</b> Comments mark the parts
598 where this is the case.
</p>
602 #ifndef CAMERA_HPP_INCLUDED
603 #define CAMERA_HPP_INCLUDED
605 #include
<boost/statechart/event.hpp
>
606 #include
<boost/statechart/state_machine.hpp
>
607 #include
<boost/statechart/simple_state.hpp
>
608 #include
<boost/statechart/custom_reaction.hpp
>
610 namespace sc = boost::statechart;
612 struct EvShutterHalf : sc::event
< EvShutterHalf
> {};
613 struct EvShutterFull : sc::event
< EvShutterFull
> {};
614 struct EvShutterRelease : sc::event
< EvShutterRelease
> {};
615 struct EvConfig : sc::event
< EvConfig
> {};
618 struct Camera : sc::state_machine
< Camera, NotShooting
>
620 bool IsMemoryAvailable() const { return true; }
621 bool IsBatteryLow() const { return false; }
625 struct NotShooting : sc::simple_state
<
626 NotShooting, Camera, Idle
>
628 // With a custom reaction we only specify that we
<b>might
</b> do
629 // something with a particular event, but the actual reaction
630 // is defined in the react member function, which can be
631 // implemented in the .cpp file.
632 <b>typedef sc::custom_reaction
< EvShutterHalf
> reactions;
</b>
635 <b>sc::result react( const EvShutterHalf
& );
</b>
638 struct Idle : sc::simple_state
< Idle, NotShooting
>
640 <b>typedef sc::custom_reaction
< EvConfig
> reactions;
</b>
643 <b>sc::result react( const EvConfig
& );
</b>
651 #include
"Camera.hpp"
653 // The following includes are only made here but not in
655 // The Shooting and Configuring states can themselves apply the
656 // same pattern to hide their inner implementation, which
657 // ensures that the two teams working on the Camera state
658 // machine will never need to disturb each other.
659 #include
"Configuring.hpp"
660 #include
"Shooting.hpp"
664 // not part of the Camera example
665 sc::result NotShooting::react( const EvShutterHalf
& )
667 return transit
< Shooting
>();
670 sc::result Idle::react( const EvConfig
& )
672 return transit
< Configuring
>();
676 <p><b><font color=
"#FF0000">Caution: Any call to
677 <code>simple_state
<>::transit
<>()
</code> or
678 <code>simple_state
<>::terminate()
</code> (see
<a href=
679 "reference.html#transit1">reference
</a>) will inevitably destruct the state
680 object (similar to
<code>delete this;
</code>)! That is, code executed after
681 any of these calls may invoke undefined behavior!
</font></b> That's why
682 these functions should only be called as part of a return statement.
</p>
684 <h3><a name=
"DeferringEvents" id=
"DeferringEvents">Deferring
687 <p>The inner workings of the Shooting state could look as follows:
</p>
689 <p><img alt=
"Camera2" src=
"Camera2.gif" border=
"0" width=
"427" height=
692 <p>When the user half-presses the shutter, Shooting and its inner initial
693 state Focusing are entered. In the Focusing entry action the camera
694 instructs the focusing circuit to bring the subject into focus. The
695 focusing circuit then moves the lenses accordingly and sends the EvInFocus
696 event as soon as it is done. Of course, the user can fully-press the
697 shutter while the lenses are still in motion. Without any precautions, the
698 resulting EvShutterFull event would simply be lost because the Focusing
699 state does not define a reaction for this event. As a result, the user
700 would have to fully-press the shutter again after the camera has finished
701 focusing. To prevent this, the EvShutterFull event is deferred inside the
702 Focusing state. This means that all events of this type are stored in a
703 separate queue, which is emptied into the main queue when the Focusing
706 struct Focusing : sc::state
< Focusing, Shooting
>
708 typedef mpl::list
<
709 sc::custom_reaction
< EvInFocus
>,
710 <b>sc::deferral
< EvShutterFull
></b>
713 Focusing( my_context ctx );
714 sc::result react( const EvInFocus
& );
718 <h3><a name=
"Guards" id=
"Guards">Guards
</a></h3>
720 <p>Both transitions originating at the Focused state are triggered by the
721 same event but they have mutually exclusive guards. Here is an appropriate
724 // not part of the Camera example
725 sc::result Focused::react( const EvShutterFull
& )
727 if ( context
< Camera
>().IsMemoryAvailable() )
729 return transit
< Storing
>();
733 // The following is actually a mixture between an in-state
734 // reaction and a transition. See later on how to implement
735 // proper transition actions.
736 std::cout
<< "Cache memory full. Please wait...\n";
737 return transit
< Focused
>();
742 <p>Custom reactions can of course also be implemented directly in the state
743 declaration, which is often preferable for easier browsing.
</p>
745 <p>Next we will use a guard to prevent a transition and let outer states
746 react to the event if the battery is low:
</p>
751 sc::result NotShooting::react( const EvShutterHalf
& )
753 if ( context
< Camera
>().IsBatteryLow() )
755 // We cannot react to the event ourselves, so we forward it
756 // to our outer state (this is also the default if a state
757 // defines no reaction for a given event).
758 <b>return forward_event();
</b>
762 return transit
< Shooting
>();
768 <h3><a name=
"InStateReactions" id=
"InStateReactions">In-state
771 <p>The self-transition of the Focused state could also be implemented as an
772 <a href=
"definitions.html#InStateReaction">in-state reaction
</a>, which has
773 the same effect as long as Focused does not have any entry or exit
779 sc::result Focused::react( const EvShutterFull
& )
781 if ( context
< Camera
>().IsMemoryAvailable() )
783 return transit
< Storing
>();
787 std::cout
<< "Cache memory full. Please wait...\n";
788 // Indicate that the event can be discarded. So, the
789 // dispatch algorithm will stop looking for a reaction
790 // and the machine remains in the Focused state.
791 <b>return discard_event();
</b>
797 <p>Because the in-state reaction is guarded, we need to employ a
798 <code>custom_reaction
<></code> here. For unguarded in-state reactions
800 "reference.html#ClassTemplatein_state_reaction">in_state_reaction
</a><></code>
801 should be used for better code-readability.
</p>
803 <h3><a name=
"TransitionActions" id=
"TransitionActions">Transition
806 <p>As an effect of every transition, actions are executed in the following
810 <li>Starting from the innermost active state, all exit actions up to but
811 excluding the
<a href=
"definitions.html#InnermostCommonContext">innermost
812 common context
</a></li>
814 <li>The transition action (if present)
</li>
816 <li>Starting from the innermost common context, all entry actions down to
817 the target state followed by the entry actions of the initial states
</li>
822 <p><img alt=
"LCA" src=
"LCA.gif" border=
"0" width=
"604" height=
"304"></p>
824 <p>Here the order is as follows: ~D(), ~C(), ~B(), ~A(), t(), X(), Y(),
825 Z(). The transition action t() is therefore executed in the context of the
826 InnermostCommonOuter state because the source state has already been left
827 (destructed) and the target state has not yet been entered
830 <p>With Boost.Statechart, a transition action can be a member of
<b>any
</b>
831 common outer context. That is, the transition between Focusing and Focused
832 could be implemented as follows:
</p>
838 struct Shooting : sc::simple_state
< Shooting, Camera, Focusing
>
840 typedef sc::transition
<
841 EvShutterRelease, NotShooting
> reactions;
844 <b>void DisplayFocused( const EvInFocus
& );
</b>
849 // not part of the Camera example
850 struct Focusing : sc::simple_state
< Focusing, Shooting
>
852 typedef sc::transition
< EvInFocus, Focused
<b>,
</b>
853 <b>Shooting,
&Shooting::DisplayFocused
</b> > reactions;
857 <p><b>Or
</b>, the following is also possible (here the state machine itself
858 serves as the outermost context):
</p>
860 // not part of the Camera example
861 struct Camera : sc::state_machine
< Camera, NotShooting
>
863 <b>void DisplayFocused( const EvInFocus
& );
</b>
867 // not part of the Camera example
868 struct Focusing : sc::simple_state
< Focusing, Shooting
>
870 typedef sc::transition
< EvInFocus, Focused
<b>,
</b>
871 <b>Camera,
&Camera::DisplayFocused
</b> > reactions;
875 <p>Naturally, transition actions can also be invoked from custom
881 sc::result Focusing::react( const EvInFocus
& evt )
883 // We have to manually forward evt
884 return transit
< Focused
>(
<b>&Shooting::DisplayFocused
</b>, evt );
888 <h2><a name=
"AdvancedTopics" id=
"AdvancedTopics">Advanced topics
</a></h2>
890 <h3><a name=
"SpecifyingMultipleReactionsForAState" id=
891 "SpecifyingMultipleReactionsForAState">Specifying multiple reactions for a
894 <p>Often a state must define reactions for more than one event. In this
895 case, an
<code>mpl::list
<></code> must be used as outlined below:
</p>
899 <b>#include
<boost/mpl/list.hpp
>
901 <b>namespace mpl = boost::mpl;
905 struct Playing : sc::simple_state
< Playing, Mp3Player
>
907 typdef
<b>mpl::list
<</b>
908 sc::custom_reaction
< EvFastForward
>,
909 sc::transition
< EvStop, Stopped
> <b>></b> reactions;
915 <h3><a name=
"PostingEvents" id=
"PostingEvents">Posting events
</a></h3>
917 <p>Non-trivial state machines often need to post internal events. Here's an
918 example of how to do this:
</p>
922 post_event( EvPumpingFinished() );
926 <p>The event is pushed into the main queue. The events in the queue are
927 processed as soon as the current reaction is completed. Events can be
928 posted from inside
<code>react
</code> functions, entry-, exit- and
929 transition actions. However, posting from inside entry actions is a bit
930 more complicated (see e.g.
<code>Focusing::Focusing()
</code> in
931 <code>Shooting.cpp
</code> in the Camera example):
</p>
933 struct Pumping :
<b>sc::state
</b>< Pumping, Purifier
>
935 <b>Pumping( my_context ctx ) : my_base( ctx )
</b>
937 post_event( EvPumpingStarted() );
943 <p>As soon as an entry action of a state needs to contact the
"outside
944 world" (here: the event queue in the state machine), the state must derive
945 from
<code>state
<></code> rather than from
946 <code>simple_state
<></code> and must implement a forwarding
947 constructor as outlined above (apart from the constructor,
948 <code>state
<></code> offers the same interface as
949 <code>simple_state
<></code>). Hence, this must be done whenever an
950 entry action makes one or more calls to the following functions:
</p>
953 <li><code>simple_state
<>::post_event()
</code></li>
956 <code>simple_state
<>::clear_shallow_history
<>()
</code></li>
958 <li><code>simple_state
<>::clear_deep_history
<>()
</code></li>
960 <li><code>simple_state
<>::outermost_context()
</code></li>
962 <li><code>simple_state
<>::context
<>()
</code></li>
964 <li><code>simple_state
<>::state_cast
<>()
</code></li>
966 <li><code>simple_state
<>::state_downcast
<>()
</code></li>
968 <li><code>simple_state
<>::state_begin()
</code></li>
970 <li><code>simple_state
<>::state_end()
</code></li>
973 <p>In my experience, these functions are needed only rarely in entry
974 actions so this workaround should not uglify user code too much.
</p>
976 <h3><a name=
"History" id=
"History">History
</a></h3>
978 <p>Photographers testing beta versions of our
<a href=
979 "#SpreadingAStateMachineOverMultipleTranslationUnits">digital camera
</a>
980 said that they really liked that half-pressing the shutter anytime (even
981 while the camera is being configured) immediately readies the camera for
982 picture-taking. However, most of them found it unintuitive that the camera
983 always goes into the idle mode after releasing the shutter. They would
984 rather see the camera go back into the state it had before half-pressing
985 the shutter. This way they can easily test the influence of a configuration
986 setting by modifying it, half- and then fully-pressing the shutter to take
987 a picture. Finally, releasing the shutter will bring them back to the
988 screen where they have modified the setting. To implement this behavior
989 we'd change the state chart as follows:
</p>
991 <p><img alt=
"CameraWithHistory1" src=
"CameraWithHistory1.gif" border=
"0"
992 width=
"542" height=
"378"></p>
994 <p>As mentioned earlier, the Configuring state contains a fairly complex
995 and deeply nested inner machine. Naturally, we'd like to restore the
996 previous state down to the
<a href=
997 "definitions.html#InnermostState">innermost state
</a>(s) in Configuring,
998 that's why we use a deep history pseudo state. The associated code looks as
1001 // not part of the Camera example
1002 struct NotShooting : sc::simple_state
<
1003 NotShooting, Camera, Idle,
<b>sc::has_deep_history
</b> >
1010 struct Shooting : sc::simple_state
< Shooting, Camera, Focusing
>
1012 typedef sc::transition
<
1013 EvShutterRelease,
<b>sc::deep_history
< Idle
></b> > reactions;
1019 <p>History has two phases: Firstly, when the state containing the history
1020 pseudo state is exited, information about the previously active inner state
1021 hierarchy must be saved. Secondly, when a transition to the history pseudo
1022 state is made later, the saved state hierarchy information must be
1023 retrieved and the appropriate states entered. The former is expressed by
1024 passing either
<code>has_shallow_history
</code>,
1025 <code>has_deep_history
</code> or
<code>has_full_history
</code> (which
1026 combines shallow and deep history) as the last parameter to the
1027 <code>simple_state
</code> and
<code>state
</code> class templates. The
1028 latter is expressed by specifying either
1029 <code>shallow_history
<></code> or
<code>deep_history
<></code>
1030 as a transition destination or, as we'll see in an instant, as an inner
1031 initial state. Because it is possible that a state containing a history
1032 pseudo state has never been entered before a transition to history is made,
1033 both class templates demand a parameter specifying the default state to
1034 enter in such situations.
</p>
1036 <p>The redundancy necessary for using history is checked for consistency at
1037 compile time. That is, the state machine wouldn't have compiled had we
1038 forgotten to pass
<code>has_deep_history
</code> to the base of
1039 <code>NotShooting
</code>.
</p>
1041 <p>Another change request filed by a few beta testers says that they would
1042 like to see the camera go back into the state it had before turning it off
1043 when they turn it back on. Here's the implementation:
</p>
1045 <p><img alt=
"CameraWithHistory2" src=
"CameraWithHistory2.gif" border=
"0"
1046 width=
"468" height=
"483"></p>
1050 // not part of the Camera example
1051 struct NotShooting : sc::simple_state
< NotShooting, Camera,
1052 <b>mpl::list
< sc::deep_history
< Idle
> ></b>,
1053 <b>sc::has_deep_history
</b> >
1061 <p>Unfortunately, there is a small inconvenience due to some
1062 template-related implementation details. When the inner initial state is a
1063 class template instantiation we always have to put it into an
1064 <code>mpl::list
<></code>, although there is only one inner initial
1065 state. Moreover, the current deep history implementation has some
<a href=
1066 "rationale.html#Limitations">limitations
</a>.
</p>
1068 <h3><a name=
"OrthogonalStates" id=
"OrthogonalStates">Orthogonal
1071 <p><img alt=
"OrthogonalStates" src=
"OrthogonalStates.gif" border=
"0" width=
1072 "633" height=
"393"></p>
1074 <p>To implement this statechart you simply specify more than one inner
1075 initial state (see the Keyboard example):
</p>
1078 struct Keyboard : sc::state_machine
< Keyboard, Active
> {};
1082 struct ScrollLockOff;
1083 struct Active: sc::simple_state
< Active, Keyboard,
1084 <b>mpl::list
< NumLockOff, CapsLockOff, ScrollLockOff
></b> > {};
1087 <p>Active's inner states must declare which orthogonal region they belong
1090 struct EvNumLockPressed : sc::event
< EvNumLockPressed
> {};
1091 struct EvCapsLockPressed : sc::event
< EvCapsLockPressed
> {};
1092 struct EvScrollLockPressed :
1093 sc::event
< EvScrollLockPressed
> {};
1095 struct NumLockOn : sc::simple_state
<
1096 NumLockOn, Active
<b>::orthogonal
< 0 ></b> >
1098 typedef sc::transition
<
1099 EvNumLockPressed, NumLockOff
> reactions;
1102 struct NumLockOff : sc::simple_state
<
1103 NumLockOff, Active
<b>::orthogonal
< 0 ></b> >
1105 typedef sc::transition
<
1106 EvNumLockPressed, NumLockOn
> reactions;
1109 struct CapsLockOn : sc::simple_state
<
1110 CapsLockOn, Active
<b>::orthogonal
< 1 ></b> >
1112 typedef sc::transition
<
1113 EvCapsLockPressed, CapsLockOff
> reactions;
1116 struct CapsLockOff : sc::simple_state
<
1117 CapsLockOff, Active
<b>::orthogonal
< 1 ></b> >
1119 typedef sc::transition
<
1120 EvCapsLockPressed, CapsLockOn
> reactions;
1123 struct ScrollLockOn : sc::simple_state
<
1124 ScrollLockOn, Active
<b>::orthogonal
< 2 ></b> >
1126 typedef sc::transition
<
1127 EvScrollLockPressed, ScrollLockOff
> reactions;
1130 struct ScrollLockOff : sc::simple_state
<
1131 ScrollLockOff, Active
<b>::orthogonal
< 2 ></b> >
1133 typedef sc::transition
<
1134 EvScrollLockPressed, ScrollLockOn
> reactions;
1138 <p><code>orthogonal
< 0 ></code> is the default, so
1139 <code>NumLockOn
</code> and
<code>NumLockOff
</code> could just as well pass
1140 <code>Active
</code> instead of
<code>Active::orthogonal
< 0 ></code>
1141 to specify their context. The numbers passed to the
<code>orthogonal
</code>
1142 member template must correspond to the list position in the outer state.
1143 Moreover, the orthogonal position of the source state of a transition must
1144 correspond to the orthogonal position of the target state. Any violations
1145 of these rules lead to compile time errors. Examples:
</p>
1147 // Example
1: does not compile because Active specifies
1148 // only
3 orthogonal regions
1149 struct WhateverLockOn: sc::simple_state
<
1150 WhateverLockOn, Active
<b>::
</b>orthogonal
< <b>3</b> > > {};
1152 // Example
2: does not compile because Active specifies
1153 // that NumLockOff is part of the
"0th" orthogonal region
1154 struct NumLockOff : sc::simple_state
<
1155 NumLockOff, Active
<b>::
</b>orthogonal
< <b>1</b> > > {};
1157 // Example
3: does not compile because a transition between
1158 // different orthogonal regions is not permitted
1159 struct CapsLockOn : sc::simple_state
<
1160 CapsLockOn, Active
<b>::
</b>orthogonal
< <b>1</b> > >
1162 typedef sc::transition
<
1163 EvCapsLockPressed, CapsLockOff
> reactions;
1166 struct CapsLockOff : sc::simple_state
<
1167 CapsLockOff, Active
<b>::
</b>orthogonal
< <b>2</b> > >
1169 typedef sc::transition
<
1170 EvCapsLockPressed, CapsLockOn
> reactions;
1174 <h3><a name=
"StateQueries" id=
"StateQueries">State queries
</a></h3>
1176 <p>Often reactions in a state machine depend on the active state in one or
1177 more orthogonal regions. This is because orthogonal regions are not
1178 completely orthogonal or a certain reaction in an outer state can only take
1179 place if the inner orthogonal regions are in particular states. For this
1180 purpose, the
<code>state_cast
<></code> function introduced under
1181 <a href=
"#GettingStateInformationOutOfTheMachine">Getting state information
1182 out of the machine
</a> is also available within states.
</p>
1184 <p>As a somewhat far-fetched example, let's assume that our
<a href=
1185 "#OrthogonalStates">keyboard
</a> also accepts
1186 <code>EvRequestShutdown
</code> events, the reception of which makes the
1187 keyboard terminate only if all lock keys are in the off state. We would
1188 then modify the Keyboard state machine as follows:
</p>
1190 struct EvRequestShutdown : sc::event
< EvRequestShutdown
> {};
1194 struct ScrollLockOff;
1195 struct Active: sc::simple_state
< Active, Keyboard,
1196 mpl::list
< NumLockOff, CapsLockOff, ScrollLockOff
> >
1198 typedef sc::custom_reaction
< EvRequestShutdown
> reactions;
1200 sc::result react( const EvRequestShutdown
& )
1202 if ( ( state_downcast
< const NumLockOff *
>() !=
0 )
&&
1203 ( state_downcast
< const CapsLockOff *
>() !=
0 )
&&
1204 ( state_downcast
< const ScrollLockOff *
>() !=
0 ) )
1210 return discard_event();
1216 <p>Passing a pointer type instead of reference type results in
0 pointers
1217 being returned instead of
<code>std::bad_cast
</code> being thrown when the
1218 cast fails. Note also the use of
<code>state_downcast
<>()
</code>
1219 instead of
<code>state_cast
<>()
</code>. Similar to the differences
1220 between
<code>boost::polymorphic_downcast
<>()
</code> and
1221 <code>dynamic_cast
</code>,
<code>state_downcast
<>()
</code> is a much
1222 faster variant of
<code>state_cast
<>()
</code> and can only be used
1223 when the passed type is a most-derived type.
1224 <code>state_cast
<>()
</code> should only be used if you want to query
1225 an additional base.
</p>
1227 <h4>Custom state queries
</h4>
1229 <p>It is often desirable to find out exactly which state(s) a machine
1230 currently resides in. To some extent this is already possible with
1231 <code>state_cast
<>()
</code> and
<code>state_downcast
<>()
</code>
1232 but their utility is rather limited because both only return a yes/no
1233 answer to the question
"Are you in state X?". It is possible to ask more
1234 sophisticated questions when you pass an additional base class rather than
1235 a state class to
<code>state_cast
<>()
</code> but this involves more
1236 work (all states need to derive from and implement the additional base), is
1237 slow (under the hood
<code>state_cast
<>()
</code> uses
1238 <code>dynamic_cast
</code>), forces projects to compile with C++ RTTI turned
1239 on and has a negative impact on state entry/exit speed.
</p>
1241 <p>Especially for debugging it would be so much more useful being able to
1242 ask
"In which state(s) are you?". For this purpose it is possible to
1243 iterate over all active
<b>innermost
</b> states with
1244 <code>state_machine
<>::state_begin()
</code> and
1245 <code>state_machine
<>::state_end()
</code>. Dereferencing the returned
1246 iterator returns a reference to
<code>const
1247 state_machine
<>::state_base_type
</code>, the common base of all
1248 states. We can thus print the currently active state configuration as
1249 follows (see the Keyboard example for the complete code):
</p>
1251 void DisplayStateConfiguration( const Keyboard
& kbd )
1256 Keyboard::state_iterator pLeafState = kbd.state_begin();
1257 pLeafState != kbd.state_end(); ++pLeafState )
1259 std::cout
<< "Orthogonal region " << region
<< ": ";
1260 // The following use of typeid assumes that
1261 // BOOST_STATECHART_USE_NATIVE_RTTI is defined
1262 std::cout
<< typeid( *pLeafState ).name()
<< "\n";
1268 <p>If necessary, the outer states can be accessed with
1269 <code>state_machine
<>::state_base_type::outer_state_ptr()
</code>,
1270 which returns a pointer to
<code>const
1271 state_machine
<>::state_base_type
</code>. When called on an outermost
1272 state this function simply returns
0.
</p>
1274 <h3><a name=
"StateTypeInformation" id=
"StateTypeInformation">State type
1275 information
</a></h3>
1277 <p>To cut down on executable size some applications must be compiled with
1278 C++ RTTI turned off. This would render the ability to iterate over all
1279 active states pretty much useless if it weren't for the following two
1283 <li><code>static
<i>unspecified_type
</i>
1284 simple_state
<>::static_type()
</code></li>
1286 <li><code><i>unspecified_type
<br></i>
1287 state_machine
<>::state_base_type::dynamic_type() const
</code></li>
1290 <p>Both return a value that is comparable via
<code>operator==()
</code> and
1291 <code>std::less
<></code>. This alone would be enough to implement the
1292 <code>DisplayStateConfiguration
</code> function above without the help of
1293 <code>typeid
</code> but it is still somewhat cumbersome as a map must be
1294 used to associate the type information values with the state names.
</p>
1296 <h4><a name=
"CustomStateTypeInformation" id=
1297 "CustomStateTypeInformation">Custom state type information
</a></h4>
1299 <p>That's why the following functions are also provided (only available
1301 "configuration.html#ApplicationDefinedMacros">BOOST_STATECHART_USE_NATIVE_RTTI
</a>
1302 is
<b>not
</b> defined):
</p>
1305 <li><code>template
< class T
><br>
1306 static void simple_state
<>::custom_static_type_ptr( const T *
1309 <li><code>template
< class T
><br>
1311 simple_state
<>::custom_static_type_ptr();
</code></li>
1313 <li><code>template
< class T
><br>
1314 const T * state_machine
<>::
<br>
1315 state_base_type::custom_dynamic_type_ptr() const;
</code></li>
1318 <p>These allow us to directly associate arbitrary state type information
1319 with each state ...
</p>
1325 NumLockOn::custom_static_type_ptr(
"NumLockOn" );
1326 NumLockOff::custom_static_type_ptr(
"NumLockOff" );
1327 CapsLockOn::custom_static_type_ptr(
"CapsLockOn" );
1328 CapsLockOff::custom_static_type_ptr(
"CapsLockOff" );
1329 ScrollLockOn::custom_static_type_ptr(
"ScrollLockOn" );
1330 ScrollLockOff::custom_static_type_ptr(
"ScrollLockOff" );
1336 <p>... and rewrite the display function as follows:
</p>
1338 void DisplayStateConfiguration( const Keyboard
& kbd )
1343 Keyboard::state_iterator pLeafState = kbd.state_begin();
1344 pLeafState != kbd.state_end(); ++pLeafState )
1346 std::cout
<< "Orthogonal region " << region
<< ": ";
1348 pLeafState-
>custom_dynamic_type_ptr
< char
>()
<< "\n";
1354 <h3><a name=
"ExceptionHandling" id=
"ExceptionHandling">Exception
1357 <p>Exceptions can be propagated from all user code except from state
1358 destructors. Out of the box, the state machine framework is configured for
1359 simple exception handling and does not catch any of these exceptions, so
1360 they are immediately propagated to the state machine client. A scope guard
1361 inside the
<code>state_machine
<></code> ensures that all state
1362 objects are destructed before the exception is caught by the client. The
1363 scope guard does not attempt to call any
<code>exit
</code> functions (see
1364 <a href=
"#TwoStageExit">Two stage exit
</a> below) that states might define
1365 as these could themselves throw other exceptions which would mask the
1366 original exception. Consequently, if a state machine should do something
1367 more sensible when exceptions are thrown, it has to catch them before they
1368 are propagated into the Boost.Statechart framework. This exception handling
1369 scheme is often appropriate but it can lead to considerable code
1370 duplication in state machines where many actions can trigger exceptions
1371 that need to be handled inside the state machine (see
<a href=
1372 "rationale.html#ErrorHandling">Error handling
</a> in the Rationale).
<br>
1373 That's why exception handling can be customized through the
1374 <code>ExceptionTranslator
</code> parameter of the
1375 <code>state_machine
</code> class template. Since the out-of-the box
1376 behavior is to
<b>not
</b> translate any exceptions, the default argument
1377 for this parameter is
<code>null_exception_translator
</code>. A
1378 <code>state_machine
<></code> subtype can be configured for advanced
1379 exception handling by specifying the library-supplied
1380 <code>exception_translator
<></code> instead. This way, the following
1381 happens when an exception is propagated from user code:
</p>
1384 <li>The exception is caught inside the framework
</li>
1386 <li>In the catch block, an
<code>exception_thrown
</code> event is
1387 allocated on the stack
</li>
1389 <li>Also in the catch block, an
<b>immediate
</b> dispatch of the
1390 <code>exception_thrown
</code> event is attempted. That is, possibly
1391 remaining events in the queue are dispatched only after the exception has
1392 been handled successfully
</li>
1394 <li>If the exception was handled successfully, the state machine returns
1395 to the client normally. If the exception could not be handled
1396 successfully, the original exception is rethrown so that the client of
1397 the state machine can handle the exception
</li>
1400 <p>On platforms with buggy exception handling implementations users would
1401 probably want to implement their own model of the
<a href=
1402 "reference.html#ExceptionTranslator">ExceptionTranslator concept
</a> (see
1403 also
<a href=
"#DiscriminatingExceptions">Discriminating
1404 exceptions
</a>).
</p>
1406 <h4>Successful exception handling
</h4>
1408 <p>An exception is considered handled successfully, if:
</p>
1411 <li>an appropriate reaction for the
<code>exception_thrown
</code> event
1412 has been found,
<b>and
</b></li>
1414 <li>the state machine is in a stable state after the reaction has
1418 <p>The second condition is important for scenarios
2 and
3 in the next
1419 section. In these scenarios, the state machine is in the middle of a
1420 transition when the exception is handled. The machine would be left in an
1421 invalid state, should the reaction simply discard the event without doing
1422 anything else.
<code>exception_translator
<></code> simply rethrows
1423 the original exception if the exception handling was unsuccessful. Just as
1424 with simple exception handling, in this case a scope guard inside the
1425 <code>state_machine
<></code> ensures that all state objects are
1426 destructed before the exception is caught by the client.
</p>
1428 <h4>Which states can react to an
<code>exception_thrown
</code> event?
</h4>
1430 <p>Short answer: If the state machine is stable when the exception is
1431 thrown, the state that caused the exception is first tried for a reaction.
1432 Otherwise the outermost
<a href=
"definitions.html#UnstableState">unstable
1433 state
</a> is first tried for a reaction.
</p>
1435 <p>Longer answer: There are three scenarios:
</p>
1438 <li>A
<code>react
</code> member function propagates an exception
1439 <b>before
</b> calling any of the reaction functions or the action
1440 executed during an in-state reaction propagates an exception. The state
1441 that caused the exception is first tried for a reaction, so the following
1442 machine will transit to Defective after receiving an EvStart event:
<br>
1444 <img alt=
"ThrowingInStateReaction" src=
"ThrowingInStateReaction.gif"
1445 border=
"0" width=
"362" height=
"182"><br>
1448 <li>A state entry action (constructor) propagates an exception:
<br>
1451 <li>If there are no orthogonal regions, the direct outer state of the
1452 state that caused the exception is first tried for a reaction, so the
1453 following machine will transit to Defective after trying to enter
1456 <img alt=
"ThrowingEntryAction" src=
"ThrowingEntryAction.gif" border=
1457 "0" width=
"438" height=
"241"><br></li>
1459 <li>If there are orthogonal regions, the outermost
<a href=
1460 "definitions.html#UnstableState">unstable state
</a> is first tried
1461 for a reaction. The outermost unstable state is found by first
1462 selecting the direct outer state of the state that caused the
1463 exception and then moving outward until a state is found that is
1464 unstable but has no direct or indirect outer states that are
1465 unstable. This more complex rule is necessary because only reactions
1466 associated with the outermost unstable state (or any of its direct or
1467 indirect outer states) are able to bring the machine back into a
1468 stable state. Consider the following statechart:
<br>
1470 <img alt=
"OutermostUnstableState" src=
"OutermostUnstableState.gif"
1471 border=
"0" width=
"467" height=
"572"><br>
1473 Whether this state machine will ultimately transition to E or F after
1474 initiation depends on which of the two orthogonal regions is
1475 initiated first. If the upper orthogonal region is initiated first,
1476 the entry sequence is as follows: A, D, B, (exception is thrown).
1477 Both D and B were successfully entered, so B is the outermost
1478 unstable state when the exception is thrown and the machine will
1479 therefore transition to F. However, if the lower orthogonal region is
1480 initiated first, the sequence is as follows: A, B, (exception is
1481 thrown). D was never entered so A is the outermost unstable state
1482 when the exception is thrown and the machine will therefore
1483 transition to E.
<br>
1484 In practice these differences rarely matter as top-level error
1485 recovery is adequate for most state machines. However, since the
1486 sequence of initiation is clearly defined (orthogonal region
0 is
1487 always initiated first, then region
1 and so forth), users
<b>can
</b>
1488 accurately control when and where they want to handle
1493 <li>A transition action propagates an exception: The innermost common
1494 outer state of the source and the target state is first tried for a
1495 reaction, so the following machine will transit to Defective after
1496 receiving an EvStartStop event:
<br>
1498 <img alt=
"ThrowingTransitionAction" src=
"ThrowingTransitionAction.gif"
1499 border=
"0" width=
"422" height=
"362"></li>
1502 <p>As with a normal event, the dispatch algorithm will move outward to find
1503 a reaction if the first tried state does not provide one (or if the
1504 reaction explicitly returned
<code>forward_event();
</code>). However,
<b>in
1505 contrast to normal events, it will give up once it has unsuccessfully tried
1506 an outermost state
</b>, so the following machine will
<b>not
</b> transit to
1507 Defective after receiving an EvNumLockPressed event:
</p>
1509 <p><img alt=
"ExceptionsAndOrthStates" src=
"ExceptionsAndOrthStates.gif"
1510 border=
"0" width=
"571" height=
"331"></p>
1512 <p>Instead, the machine is terminated and the original exception
1515 <h4><a name=
"DiscriminatingExceptions" id=
1516 "DiscriminatingExceptions">Discriminating exceptions
</a></h4>
1518 <p>Because the
<code>exception_thrown
</code> event is dispatched from
1519 within the catch block, we can rethrow and catch the exception in a custom
1522 struct Defective : sc::simple_state
<
1523 Defective, Purifier
> {};
1525 // Pretend this is a state deeply nested in the Purifier
1527 struct Idle : sc::simple_state
< Idle, Purifier
>
1529 typedef mpl::list
<
1530 sc::custom_reaction
< EvStart
>,
1531 sc::custom_reaction
< sc::exception_thrown
>
1534 sc::result react( const EvStart
& )
1536 throw std::runtime_error(
"" );
1539 sc::result react( const sc::exception_thrown
& )
1545 catch ( const std::runtime_error
& )
1547 // only std::runtime_errors will lead to a transition
1549 return transit
< Defective
>();
1553 // ... all other exceptions are forwarded to our outer
1554 // state(s). The state machine is terminated and the
1555 // exception rethrown if the outer state(s) can't
1556 // handle it either...
1557 return forward_event();
1560 // Alternatively, if we want to terminate the machine
1561 // immediately, we can also either rethrow or throw
1562 // a different exception.
1567 <p><b>Unfortunately, this idiom (using
<code>throw;
</code> inside a
1568 <code>try
</code> block nested inside a
<code>catch
</code> block) does not
1569 work on at least one very popular compiler.
</b> If you have to use one of
1570 these platforms, you can pass a customized exception translator class to
1571 the
<code>state_machine
</code> class template. This will allow you to
1572 generate different events depending on the type of the exception.
</p>
1574 <h4><a name=
"TwoStageExit" id=
"TwoStageExit">Two stage exit
</a></h4>
1576 <p>If a
<code>simple_state
<></code> or
<code>state
<></code>
1577 subtype declares a public member function with the signature
<code>void
1578 exit()
</code> then this function is called just before the state object is
1579 destructed. As explained under
<a href=
"rationale.html#ErrorHandling">Error
1580 handling
</a> in the Rationale, this is useful for two things that would
1581 otherwise be difficult or cumbersome to achieve with destructors only:
</p>
1584 <li>To signal a failure in an exit action
</li>
1586 <li>To execute certain exit actions
<b>only
</b> during a transition or a
1587 termination but not when the state machine object is destructed
</li>
1590 <p>A few points to consider before employing
<code>exit()
</code>:
</p>
1593 <li>There is no guarantee that
<code>exit()
</code> will be called:
1596 <li>If the client destructs the state machine object without calling
1597 <code>terminate()
</code> beforehand then the currently active states
1598 are destructed without calling
<code>exit()
</code>. This is necessary
1599 because an exception that is possibly thrown from
<code>exit()
</code>
1600 could not be propagated on to the state machine client
</li>
1602 <li><code>exit()
</code> is not called when a previously executed
1603 action propagated an exception and that exception has not (yet) been
1604 handled successfully. This is because a new exception that could
1605 possibly be thrown from
<code>exit()
</code> would mask the original
1610 <li>A state is considered exited, even if its
<code>exit
</code> function
1611 propagated an exception. That is, the state object is inevitably
1612 destructed right after calling
<code>exit()
</code>, regardless of whether
1613 <code>exit()
</code> propagated an exception or not. A state machine
1614 configured for advanced exception handling is therefore always unstable
1615 while handling an exception propagated from an
<code>exit
</code>
1618 <li>In a state machine configured for advanced exception handling the
1619 processing rules for an exception event resulting from an exception
1620 propagated from
<code>exit()
</code> are analogous to the ones defined for
1621 exceptions propagated from state constructors. That is, the outermost
1622 unstable state is first tried for a reaction and the dispatcher then
1623 moves outward until an appropriate reaction is found
</li>
1626 <h3><a name=
"SubmachinesAndParameterizedStates" id=
1627 "SubmachinesAndParameterizedStates">Submachines
& parameterized
1630 <p>Submachines are to event-driven programming what functions are to
1631 procedural programming, reusable building blocks implementing often needed
1632 functionality. The associated UML notation is not entirely clear to me. It
1633 seems to be severely limited (e.g. the same submachine cannot appear in
1634 different orthogonal regions) and does not seem to account for obvious
1635 stuff like e.g. parameters.
</p>
1637 <p>Boost.Statechart is completely unaware of submachines but they can be
1638 implemented quite nicely with templates. Here, a submachine is used to
1639 improve the copy-paste implementation of the keyboard machine discussed
1640 under
<a href=
"#OrthogonalStates">Orthogonal states
</a>:
</p>
1649 template
< LockType lockType
>
1651 struct Active : sc::simple_state
<
1652 Active, Keyboard, mpl::list
<
1653 Off
< NUM_LOCK
>, Off
< CAPS_LOCK
>, Off
< SCROLL_LOCK
> > > {};
1655 template
< LockType lockType
>
1656 struct EvPressed : sc::event
< EvPressed
< lockType
> > {};
1658 template
< LockType lockType
>
1659 struct On : sc::simple_state
<
1660 On
< lockType
>, Active::orthogonal
< lockType
> >
1662 typedef sc::transition
<
1663 EvPressed
< lockType
>, Off
< lockType
> > reactions;
1666 template
< LockType lockType
>
1667 struct Off : sc::simple_state
<
1668 Off
< lockType
>, Active::orthogonal
< lockType
> >
1670 typedef sc::transition
<
1671 EvPressed
< lockType
>, On
< lockType
> > reactions;
1675 <h3><a name=
"AsynchronousStateMachines" id=
1676 "AsynchronousStateMachines">Asynchronous state machines
</a></h3>
1678 <h4>Why asynchronous state machines are necessary
</h4>
1680 <p>As the name suggests, a synchronous state machine processes each event
1681 synchronously. This behavior is implemented by the
1682 <code>state_machine
</code> class template, whose
<code>process_event
</code>
1683 function only returns after having executed all reactions (including the
1684 ones provoked by internal events that actions might have posted). This
1685 function is strictly non-reentrant (just like all other member functions,
1686 so
<code>state_machine
<></code> is not thread-safe). This makes it
1687 difficult for two
<code>state_machine
<></code> subtype objects to
1688 communicate via events in a bi-directional fashion correctly,
<b>even in a
1689 single-threaded program
</b>. For example, state machine
<code>A
</code> is
1690 in the middle of processing an external event. Inside an action, it decides
1691 to send a new event to state machine
<code>B
</code> (by calling
1692 <code>B::process_event()
</code>). It then
"waits" for B to send back an
1693 answer via a
<code>boost::function
<></code>-like call-back, which
1694 references
<code>A::process_event()
</code> and was passed as a data member
1695 of the event. However, while
<code>A
</code> is
"waiting" for
<code>B
</code>
1696 to send back an event,
<code>A::process_event()
</code> has not yet returned
1697 from processing the external event and as soon as
<code>B
</code> answers
1698 via the call-back,
<code>A::process_event()
</code> is
<b>unavoidably
</b>
1699 reentered. This all really happens in a single thread, that's why
"wait" is
1702 <h4>How it works
</h4>
1704 <p>The
<code>asynchronous_state_machine
</code> class template has none of
1705 the member functions the
<code>state_machine
</code> class template has.
1706 Moreover,
<code>asynchronous_state_machine
<></code> subtype objects
1707 cannot even be created or destroyed directly. Instead, all these operations
1708 must be performed through the
<code>Scheduler
</code> object each
1709 asynchronous state machine is associated with. All these
1710 <code>Scheduler
</code> member functions only push an appropriate item into
1711 the schedulers' queue and then return immediately. A dedicated thread will
1712 later pop the items out of the queue to have them processed.
</p>
1714 <p>Applications will usually first create a
1715 <code>fifo_scheduler
<></code> object and then call
1716 <code>fifo_scheduler
<>::create_processor
<>()
</code> and
1717 <code>fifo_scheduler
<>::initiate_processor()
</code> to schedule the
1718 creation and initiation of one or more
1719 <code>asynchronous_state_machine
<></code> subtype objects. Finally,
1720 <code>fifo_scheduler
<>::operator()()
</code> is either called directly
1721 to let the machine(s) run in the current thread, or, a
1722 <code>boost::function
<></code> object referencing
1723 <code>operator()()
</code> is passed to a new
<code>boost::thread
</code>.
1724 Alternatively, the latter could also be done right after constructing the
1725 <code>fifo_scheduler
<></code> object. In the following code, we are
1726 running one state machine in a new
<code>boost::thread
</code> and the other
1727 in the main thread (see the PingPong example for the full source code):
</p>
1731 sc::asynchronous_state_machine
< Player, Waiting
>
1740 // Create two schedulers that will wait for new events
1741 // when their event queue runs empty
1742 sc::fifo_scheduler
<> scheduler1( true );
1743 sc::fifo_scheduler
<> scheduler2( true );
1745 // Each player is serviced by its own scheduler
1746 sc::fifo_scheduler
<>::processor_handle player1 =
1747 scheduler1.create_processor
< Player
>( /* ... */ );
1748 scheduler1.initiate_processor( player1 );
1749 sc::fifo_scheduler
<>::processor_handle player2 =
1750 scheduler2.create_processor
< Player
>( /* ... */ );
1751 scheduler2.initiate_processor( player2 );
1753 // the initial event that will start the game
1754 boost::intrusive_ptr
< BallReturned
> pInitialBall =
1759 scheduler2.queue_event( player2, pInitialBall );
1763 // Up until here no state machines exist yet. They
1764 // will be created when operator()() is called
1766 // Run first scheduler in a new thread
1767 boost::thread otherThread( boost::bind(
1768 &sc::fifo_scheduler
<>::operator(),
&scheduler1,
0 ) );
1769 scheduler2(); // Run second scheduler in this thread
1776 <p>We could just as well use two boost::threads:
</p>
1782 boost::thread thread1( boost::bind(
1783 &sc::fifo_scheduler
<>::operator(),
&scheduler1,
0 ) );
1784 boost::thread thread2( boost::bind(
1785 &sc::fifo_scheduler
<>::operator(),
&scheduler2,
0 ) );
1787 // do something else ...
1796 <p>Or, run both machines in the same thread:
</p>
1800 sc::fifo_scheduler
<> scheduler1( true );
1802 sc::fifo_scheduler
<>::processor_handle player1 =
1803 scheduler1.create_processor
< Player
>( /* ... */ );
1804 sc::fifo_scheduler
<>::processor_handle player2 =
1805 scheduler1.create_processor
< Player
>( /* ... */ );
1815 <p>In all the examples above,
1816 <code>fifo_scheduler
<>::operator()()
</code> waits on an empty event
1817 queue and will only return after a call to
1818 <code>fifo_scheduler
<>::terminate()
</code>. The
<code>Player
</code>
1819 state machine calls this function on its scheduler object right before
1823 <p><a href=
"http://validator.w3.org/check?uri=referer"><img border=
"0" src=
1824 "../../../doc/images/valid-html401.png" alt=
"Valid HTML 4.01 Transitional"
1825 height=
"31" width=
"88"></a></p>
1828 <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->03 December,
2006<!--webbot bot="Timestamp" endspan i-checksum="38512" --></p>
1830 <p><i>Copyright
© 2003-
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%Y" startspan -->2006<!--webbot bot="Timestamp" endspan i-checksum="770" -->
1831 <a href=
"contact.html">Andreas Huber D
önni
</a></i></p>
1833 <p><i>Distributed under the Boost Software License, Version
1.0. (See
1834 accompanying file
<a href=
"../../../LICENSE_1_0.txt">LICENSE_1_0.txt
</a> or
1836 "http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt
</a>)
</i></p>