Files
statechart/doc/tutorial.html
Andreas Huber 7e681d0169 Various clarifications and corrections
[SVN r22680]
2004-04-21 07:12:06 +00:00

1369 lines
63 KiB
HTML
Raw Blame History

<html>
<head>
<meta http-equiv="Content-Language" content="en-us">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<link rel="stylesheet" type="text/css" href="../../../boost.css">
<title>The boost::fsm library - Tutorial</title>
</head>
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary="header">
<tr>
<td valign="top" width="300">
<h3><a href="../../../index.htm">
<img alt="C++ Boost" src="../../../c++boost.gif" border="0" width="277" height="86"></a></h3>
</td>
<td valign="top">
<h1 align="center">The boost::fsm library</h1>
<h2 align="center">Tutorial</h2>
</td>
</tr>
</table>
<hr>
<p>The Japanese translation of this tutorial can be found at
<a href="http://prdownloads.sourceforge.jp/jyugem/7127/fsm-tutorial-jp.pdf">
http://prdownloads.sourceforge.jp/jyugem/7127/fsm-tutorial-jp.pdf</a>. Kindly
contributed by Mitsuo Fukasawa.</p>
<h2>Contents</h2>
<dl class="page-index">
<dt><a href="#Introduction">Introduction</a></dt>
<dd><a href="#Audience">Audience</a></dd>
<dd><a href="#How to read this tutorial">How to read this tutorial</a></dd>
<dt><a href="#Hello World!">Hello World!</a></dt>
<dt><a href="#A stop watch">A stop watch</a></dt>
<dd><a href="#Defining states and events">Defining states and events</a></dd>
<dd><a href="#Adding reactions">Adding reactions</a></dd>
<dd><a href="#State-local storage">State-local storage</a></dd>
<dd><a href="#Getting state information out of the machine">Getting state
information out of the machine</a></dd>
<dt><a href="#A digital camera">A digital camera</a></dt>
<dd><a href="#Spreading a state machine over multiple translation units">
Spreading a state machine over multiple translation units</a></dd>
<dd><a href="#Deferring events">Deferring events</a></dd>
<dd><a href="#Guards">Guards</a></dd>
<dd><a href="#In-state reactions">In-state reactions</a></dd>
<dd><a href="#Transition actions">Transition actions</a></dd>
<dt><a href="#Advanced topics">Advanced topics</a></dt>
<dd><a href="#Specifying multiple reactions for a state">Specifying multiple
reactions for a state</a></dd>
<dd><a href="#Posting events">Posting events</a></dd>
<dd><a href="#History">History</a></dd>
<dd><a href="#Orthogonal states">Orthogonal states</a></dd>
<dd><a href="#State queries">State queries</a></dd>
<dd><a href="#State type information">State type information</a></dd>
<dd><a href="#Exception handling">Exception handling</a></dd>
<dd><a href="#Submachines & Parametrized States">Submachines &amp; Parametrized
States</a></dd>
<dd><a href="#Asynchronous state machines">Asynchronous state machines</a></dd>
</dl>
<hr>
<h2><a name="Introduction">Introduction</a></h2>
<p>The boost::fsm library is a framework that allows you to quickly transform
a UML state chart into executable C++ code, <b>without</b> needing to use a
code generator. Thanks to support for almost all UML features the
transformation is straight-forward and the resulting C++ code is a nearly
redundancy-free textual description of the state chart.</p>
<p>All examples have been tested on the following platforms using boost
distribution 1.31.0:</p>
<ul>
<li>MSVC7.1 (the compiler coming with Visual Studio .NET 2003)</li>
<li>GCC3.2 (MinGW, Red Hat Linux)</li>
<li>Intel8.0 (Win32)</li>
</ul>
<p><b><font color="#FF0000">Caution: Bugs in atomic_count_gcc.hpp break
boost::fsm on Linux! Please see readme.txt in </font>
<a href="http://boost-sandbox.sf.net/fsm.zip"><font color="#FF0000">
http://boost-sandbox.sf.net/fsm.zip</font></a><font color="#FF0000"> on how to
fix this.</font></b></p>
<h3><a name="Audience">Audience</a></h3>
<p>Throughout all boost::fsm documentation it is assumed that the reader is
familiar with the state machine concept, UML state charts and most of the UML
state machine terminology. The following links might be interesting if this is
not the case:</p>
<ul>
<li><a href="http://www.objectmentor.com/resources/articles/umlfsm.pdf">
http://www.objectmentor.com/resources/articles/umlfsm.pdf</a> introduces
state machines and UML state charts</li>
<li>
<a href="http://www.sts.tu-harburg.de/teaching/ws-99.00/OOA+D/StateDiagrams.pdf">
http://www.sts.tu-harburg.de/teaching/ws-99.00/OOA+D/StateDiagrams.pdf</a>
explains most of the UML state chart elements and terminology</li>
<li>The inventor of state charts, David Harel, presents a thorough but still
very readable discussion in his original paper:
<a href="http://www.wisdom.weizmann.ac.il/~dharel/SCANNED.PAPERS/Statecharts.pdf">
http://www.wisdom.weizmann.ac.il/~dharel/SCANNED.PAPERS/Statecharts.pdf</a></li>
<li>The UML specifications (formal) can be found here:
<a href="http://www.omg.org/cgi-bin/doc?formal/03-03-01">
http://www.omg.org/cgi-bin/doc?formal/03-03-01</a> (see chapters 2.12 and
3.74)</li>
</ul>
<p>Some of the used terminology cannot be found in the UML specifications,
please see <a href="definitions.html">Definitions</a> for more information.</p>
<h3><a name="How to read this tutorial">How to read this tutorial</a></h3>
<p>This tutorial was designed to be read linearly. First time users should
start reading right at the beginning and stop as soon as they know enough for
the task at hand. Specifically:</p>
<ul>
<li>The tutorial starts out with the <a href="#Hello World!">Hello World!</a>
and <a href="#A stop watch">stop watch</a> examples explaining the most
basic features that all users of the library should understand. Small and
simple machines with just a handful of states can be implemented reasonably
well by using just these features.</li>
<li>Afterwards, the <a href="#A digital camera">digital camera</a> example
explains the intermediate features most of which should be known by anyone
wanting to build larger machines with up to roughly a dozen states.</li>
<li>Finally, users wanting to create even more complex machines and project
architects evaluating boost::fsm should also read the
<a href="#Advanced topics">Advanced topics</a> section at the end. Moreover,
reading the <a href="rationale.html#Limitations">Limitations</a> section in
the Rationale is strongly suggested.</li>
</ul>
<h2><a name="Hello World!">Hello World!</a></h2>
<p>We will use the simplest possible program to make our first steps. The
state chart ...</p>
<p><img border="0" src="HelloWorld.gif" width="379" height="94"></p>
<p>... is implemented with the following code:</p>
<pre>#include &lt;boost/fsm/state_machine.hpp&gt;
#include &lt;boost/fsm/simple_state.hpp&gt;
#include &lt;iostream&gt;
namespace fsm = boost::fsm;
struct Greeting;
struct Machine : fsm::state_machine&lt; Machine, Greeting &gt; {};
struct Greeting : fsm::simple_state&lt; Greeting, Machine &gt;
{
Greeting() { std::cout &lt;&lt; &quot;Hello World!\n&quot;; } // entry
~Greeting() { std::cout &lt;&lt; &quot;Bye Bye World!\n&quot;; } // exit
};
int main()
{
Machine myMachine;
myMachine.initiate();
return 0;
}</pre>
<p>This prints <code>Hello World!</code> and <code>Bye Bye World!</code>
before exiting. The first line is printed as a result of calling <code>
initiate()</code>, which leads to the <code>Greeting</code> state begin
entered. At the end of <code>main()</code>, the <code>myMachine</code> object
is destroyed what automatically exits the <code>Greeting</code> state.</p>
<p>A few remarks:</p>
<ul>
<li>boost::fsm makes heavy use of the
<a href="http://www.informit.com/articles/article.asp?p=31473&seqNum=3">
curiously recurring template pattern</a>. The deriving class must always be
passed as the first parameter to all base class templates</li>
<li>The state machine must be informed which state it has to enter when the
machine is initiated. That's why <code>Greeting</code> is passed as the
second template parameter of <code>Machine</code>'s base. We have to forward
declare <code>Greeting</code> for this purpose</li>
<li>For each state we need to define which state machine it belongs to and
where it is located in the state chart. Both is specified with <code>Context</code>
argument that is passed to <code>simple_state&lt;&gt;</code>. For a flat state
machine as we have it here, the context is always the state machine.
Consequently, <code>Machine</code> must be passed as the second template
parameter to <code>Greeting</code>'s base (the <code>Context</code>
parameter is explained in more detail in the next example)</li>
<li>Whenever the state machine enters a state, it creates an object of the
corresponding state class. The object is then kept alive as long as the
machine remains in the state. Finally, the object is destroyed when the
state machine exits the state. Therefore, a state entry action can be
defined by adding a constructor and a state exit action can be defined by
adding a destructor</li>
<li>The machine is not yet running after construction. We start it by
calling <code>initiate()</code></li>
<li>We are declaring all types as <code>struct</code>s only to avoid having
to type <code>public</code>. If you don't mind doing so, you can just as
well use <code>class</code></li>
</ul>
<h2><a name="A stop watch">A stop watch</a></h2>
<p>Next we will model a simple mechanical stop watch with a state machine.
Such watches typically have two buttons:</p>
<ul>
<li>Start/Stop</li>
<li>Reset</li>
</ul>
<p>And two states:</p>
<ul>
<li>Stopped: The hands reside in the position where they were last stopped:<ul>
<li>Pressing the reset button moves the hands back to the 0 position. The
watch remains in the Stopped state</li>
<li>Pressing the start/stop button leads to a transition to the Running
state</li>
</ul>
</li>
<li>Running: The hands of the watch are in motion and continually show the
elapsed time<ul>
<li>Pressing the reset button moves the hands back to the 0 position and
leads to a transition to the Stopped state</li>
<li>Pressing the start/stop button leads to a transition to the Stopped
state</li>
</ul>
</li>
</ul>
<p>Here is one way to specify this in UML:</p>
<p><img border="0" src="StopWatch.gif" width="560" height="184"></p>
<h3><a name="Defining states and events">Defining states and events</a></h3>
<p>The two buttons are modeled by two events. Moreover, we also define the
necessary states and the initial state. <b>The following code is our starting
point, subsequent code snippets must be inserted</b>:</p>
<pre>#include &lt;boost/fsm/event.hpp&gt;
#include &lt;boost/fsm/state_machine.hpp&gt;
#include &lt;boost/fsm/simple_state.hpp&gt;
namespace fsm = boost::fsm;
struct EvStartStop : fsm::event&lt; EvStartStop &gt; {};
struct EvReset : fsm::event&lt; EvReset &gt; {};
struct Active;
struct StopWatch : fsm::state_machine&lt; StopWatch, Active &gt; {};
struct Stopped;
struct Active : fsm::simple_state&lt; Active, StopWatch,
fsm::no_reactions, Stopped &gt; {};
struct Running : fsm::simple_state&lt; Running, Active &gt; {};
struct Stopped : fsm::simple_state&lt; Stopped, Active &gt; {};
int main()
{
StopWatch myWatch;
myWatch.initiate();
return 0;
}</pre>
<p>This compiles but doesn't do anything observable yet. A few comments:</p>
<ul>
<li>The <code>simple_state</code> class template accepts up to five
parameters:<ul>
<li>The third parameter specifies <a href="definitions.html#Reaction">
reactions</a> (explained in due course). Because there aren't any yet, we
pass <code>no_reactions</code>, which is also the default</li>
<li>The fourth parameter specifies the inner initial state, if there is
one. Here, only Active has inner states, which is why it needs to pass its
inner initial state Stopped to its base</li>
<li>The fifth parameter specifies whether and what kind of history is kept</li>
</ul>
</li>
<li>A state is defined as an inner state simply by passing its outer state
as its <code>Context</code> parameter (where
<a href="definitions.html#Outermost state">outermost states</a> pass the
state machine). Here, <code>Active</code> is the outermost state and
therefore needs to pass the state machine class it belongs to. <code>Stopped</code>
and <code>Running</code> both specify <code>Active</code> as their <code>
Context</code>, which makes them nested inside <code>Active</code></li>
<li>Because the context of a state must be a complete type (i.e. not forward
declared), a machine must be defined from &quot;outside to inside&quot;. That is, we
always start with the state machine, followed by outermost states, followed
by the direct inner states of outermost states and so on. We can do so in a
breadth-first or depth-first way or employ a mixture of the two.<br>
Since the source and destination state of a transition often have the same
nesting depth, the pure depth-first approach tends to require a lot of
forward declarations for transition destinations while the pure
breadth-first approach tends to minimize the number of necessary forward
declarations.</li>
</ul>
<h3><a name="Adding reactions">Adding reactions</a></h3>
<p>For the moment we will use only one type of reaction: transitions. We <b>
insert</b> the bold parts of the following code:</p>
<pre><b>#include &lt;boost/fsm/transition.hpp&gt;
</b>
// ...
struct Stopped;
struct Active : fsm::simple_state&lt; Active, StopWatch,
<b>fsm::transition&lt; EvReset, Active &gt;</b>, Stopped &gt; {};
struct Running : fsm::simple_state&lt; Running, Active<b>,
</b> <b>fsm::transition&lt; EvStartStop, Stopped &gt;</b> &gt; {};
struct Stopped : fsm::simple_state&lt; Stopped, Active<b>,
</b> <b>fsm::transition&lt; EvStartStop, Running &gt;</b> &gt; {};
int main()
{
StopWatch myWatch;
myWatch.initiate();
<b>myWatch.process_event( EvStartStop() );
</b> <b>myWatch.process_event( EvStartStop() );
</b> <b>myWatch.process_event( EvStartStop() );
</b> <b>myWatch.process_event( EvReset() );
</b> return 0;
}</pre>
<p>A state can define an arbitrary number of reactions. That's why we have to
put them into an <code>mpl::list&lt;&gt;</code> as soon as there is more than one of
them (see <a href="#Specifying multiple reactions for a state">Specifying
multiple reactions for a state</a>).<br>
Now we have all the states and all the transitions in place and a number of
events are also sent to the stop watch. The machine dutifully makes the
transitions we would expect, but no actions are executed yet.</p>
<h3><a name="State-local storage">State-local storage</a></h3>
<p>Next we'll make the stop watch actually measure time. Depending on the
state the stop watch is in, we need different variables:</p>
<ul>
<li>Stopped: One variable holding the elapsed time</li>
<li>Running: One variable holding the elapsed time <b>and</b> one variable
storing the point in time at which the watch was last started.</li>
</ul>
<p>We observe that the elapsed time variable is needed no matter what state
the machine is in. Moreover, this variable should be reset to 0 when we send
an <code>EvReset</code> event to the machine. The other variable is only
needed while the machine is in the Running state. It should be set to the
current time of the system clock whenever we enter the Running state. Upon
exit we simply subtract the start time from the current system clock time and
add the result to the elapsed time.</p>
<pre><b>#include &lt;ctime&gt;
</b>
// ...
struct Stopped;
struct Active : fsm::simple_state&lt; Active, StopWatch,
fsm::transition&lt; EvReset, Active &gt;, Stopped &gt;
{
<b>public:
</b> <b>Active() : elapsedTime_( 0.0 ) {}
</b> <b>double ElapsedTime() const { return elapsedTime_; }
</b> <b>double &amp; ElapsedTime() { return elapsedTime_; }
</b> <b>private:
</b> <b>double elapsedTime_;
</b>};
struct Running : fsm::simple_state&lt; Running, Active,
fsm::transition&lt; EvStartStop, Stopped &gt; &gt;
{
<b>public:
</b> <b>Running() : startTime_( std::time( 0 ) ) {}
</b> <b>~Running()
</b> <b>{
</b> <b>context&lt; Active &gt;().ElapsedTime() +=
</b> <b>std::difftime( std::time( 0 ), startTime_ );
</b> <b>}
</b> <b>private:
</b> <b>std::time_t startTime_;
</b>};
// ...</pre>
<p>Similar to when a derived class object accesses its base class portion,
<code>context&lt;&gt;()</code> is used to gain access to the direct or indirect
context of a state. This can either be a direct or indirect outer state (e.g.
<code>context&lt; Active &gt;()</code>) or the state machine itself (<code>context&lt;
StopWatch &gt;()</code>). The rest should be mostly self-explanatory. The machine
now measures the time, but we cannot yet retrieve it from the main program.</p>
<h3><a name="Getting state information out of the machine">Getting state
information out of the machine</a></h3>
<p>To retrieve the measured time, we need a mechanism to get state information
out of the machine. With our current machine design there are two ways to do
that. For the sake of simplicity we use the less efficient one: <code>
state_cast&lt;&gt;()</code> (StopWatch2.cpp shows the slightly more complex
alternative). As the name suggests, the semantics are very similar to the ones
of <code>dynamic_cast</code>. For example, when we call <code>
myWatch.state_cast&lt; const Stopped &amp; &gt;()</code> <b>and</b> the machine is
currently in the Stopped state, we get a reference to the <code>Stopped</code>
state. Otherwise <code>std::bad_cast</code> is thrown. We can use this
functionality to implement a <code>StopWatch</code> member function that
returns the elapsed time. However, rather than ask the machine in which state
it is and then switch to different calculations for the elapsed time, we put
the calculation into the Stopped and Running states and use an interface to
retrieve the elapsed time:</p>
<pre><b>#include &lt;iostream&gt;
</b>// ...
<b>struct IElapsedTime
{
</b> <b>virtual double ElapsedTime() const = 0;
};
</b>struct Active;
struct StopWatch : fsm::state_machine&lt; StopWatch, Active &gt;
{
<b>double ElapsedTime() const
</b> <b>{
</b> <b>return state_cast&lt; const IElapsedTime &amp; &gt;().ElapsedTime();
</b> <b>}
</b>};
<b>
</b>// ...
struct Running : <b>IElapsedTime,</b> fsm::simple_state&lt;
Running, Active, fsm::transition&lt; EvStartStop, Stopped &gt; &gt;
{
public:
Running() : startTime_( std::time( 0 ) ) {}
~Running()
{
<b>context&lt; Active &gt;().ElapsedTime() = ElapsedTime();
</b> }
<b>
</b> <b>virtual double ElapsedTime() const
</b> <b>{
</b> <b>return context&lt; Active &gt;().ElapsedTime() +
</b> <b>std::difftime( std::time( 0 ), startTime_ );
</b> <b>}
</b> private:
std::time_t startTime_;
};
struct Stopped : <b>IElapsedTime,</b> fsm::simple_state&lt;
Stopped, Active, fsm::transition&lt; EvStartStop, Running &gt; &gt;
{
<b>virtual double ElapsedTime() const
</b> <b>{
</b> <b>return context&lt; Active &gt;().ElapsedTime();
</b> <b>}
</b>};
int main()
{
StopWatch myWatch;
myWatch.initiate();
<b>std::cout &lt;&lt; myWatch.ElapsedTime() &lt;&lt; &quot;\n&quot;;
</b> myWatch.process_event( EvStartStop() );
<b>std::cout &lt;&lt; myWatch.ElapsedTime() &lt;&lt; &quot;\n&quot;;
</b> myWatch.process_event( EvStartStop() );
<b>std::cout &lt;&lt; myWatch.ElapsedTime() &lt;&lt; &quot;\n&quot;;
</b> myWatch.process_event( EvStartStop() );
<b>std::cout &lt;&lt; myWatch.ElapsedTime() &lt;&lt; &quot;\n&quot;;
</b> myWatch.process_event( EvReset() );
<b>std::cout &lt;&lt; myWatch.ElapsedTime() &lt;&lt; &quot;\n&quot;;
</b> return 0;
}</pre>
<p>To actually see time being measured, you might want to single-step through
the statements in <code>main()</code>. The StopWatch example extends this
program to an interactive console application.</p>
<h2><a name="A digital camera">A digital camera</a></h2>
<p>So far so good. However, the approach presented above has a few
limitations:</p>
<ul>
<li>Bad scalability: As soon as the compiler reaches the point where <code>
state_machine::initiate()</code> is called, a number of template
instantiations take place, which can only succeed if the full declaration of
each and every state of the machine is known. That is, the whole layout of a
state machine must be implemented in one single translation unit (actions
can be compiled separately, but this is of no importance here). For bigger
(and more real-world) state machines, this leads to the following
limitations:<ul>
<li>At some point compilers reach their internal template instantiation
limits and give up. This can happen even for moderately-sized machines.
For example, in debug mode one popular compiler refused to compile earlier
versions of the BitMachine example for anything above 3 bits. This means
that the compiler reached its limits somewhere between 8 states, 24
transitions and 16 states, 64 transitions</li>
<li>Multiple programmers can hardly work on the same state machine
simultaneously because every layout change will inevitably lead to a
recompilation of the whole state machine</li>
</ul>
</li>
<li>Maximum one reaction per event: According to UML a state can have
multiple reactions triggered by the same event. This makes sense when all
reactions have mutually exclusive guards. The interface we used above only
allows for at most one unguarded reaction for each event. Moreover, the UML
concepts junction and choice point are not directly supported</li>
<li>There is no way to specify <a href="definitions.html#In-state reaction">
in-state reactions</a></li>
</ul>
<p>All these limitations can be overcome with custom reactions. <b>Warning: It
is easy to abuse custom reactions up to the point of invoking undefined
behavior. Please study the documentation before employing them!</b></p>
<h3><a name="Spreading a state machine over multiple translation units">
Spreading a state machine over multiple translation units</a></h3>
<p>Let's say your company would like to develop a digital camera. The camera
has the following controls:</p>
<ul>
<li>Shutter button, which can be half-pressed and fully-pressed. The
associated events are <code>EvShutterHalf</code>, <code>EvShutterFull</code>
and <code>EvShutterReleased</code></li>
<li>Config button, represented by the <code>EvConfig</code> event</li>
<li>A number of other buttons that are not of interest here</li>
</ul>
<p>One use case for the camera says that the photographer can half-press the
shutter <b>anywhere</b> in the configuration mode and the camera will
immediately go into shooting mode. The following state chart is one way to
achieve this behavior:</p>
<p><img border="0" src="Camera.gif" width="544" height="317"></p>
<p>The Configuring and Shooting states will contain numerous nested states
while the Idle state is relatively simple. It was therefore decided to build
two teams. One will implement the shooting mode while the other will implement
the configuration mode. The two teams have already agreed on the interface
that the shooting team will use to retrieve the configuration settings. We
would like to ensure that the two teams can work with the least possible
interference. So, we put the two states in their own translation units so that
machine layout changes within the Configuring state will never lead to a
recompilation of the inner workings of the Shooting state and vice versa.</p>
<p><b>Unlike in the previous example, the excerpts presented here often
outline different options to achieve the same effect. That's why the code is
often not equal to the Camera example code.</b> Comments mark the parts where
this is the case.</p>
<p>Camera.hpp:</p>
<pre>#ifndef CAMERA_HPP
#define CAMERA_HPP
#include &lt;boost/fsm/event.hpp&gt;
#include &lt;boost/fsm/state_machine.hpp&gt;
#include &lt;boost/fsm/simple_state.hpp&gt;
#include &lt;boost/fsm/custom_reaction.hpp&gt;
namespace fsm = boost::fsm;
struct EvShutterHalf : fsm::event&lt; EvShutterHalf &gt; {};
struct EvShutterFull : fsm::event&lt; EvShutterFull &gt; {};
struct EvShutterRelease : fsm::event&lt; EvShutterRelease &gt; {};
struct EvConfig : fsm::event&lt; EvConfig &gt; {};
struct NotShooting;
struct Camera : fsm::state_machine&lt; Camera, NotShooting &gt;
{
bool IsMemoryAvailable() const { return true; }
bool IsBatteryLow() const { return false; }
};
struct Idle;
struct NotShooting : fsm::simple_state&lt; NotShooting, Camera,
<b>fsm::custom_reaction&lt; EvShutterHalf &gt;</b>, Idle &gt;
{
// ...
<b>fsm::result react( const EvShutterHalf &amp; );</b>
};
struct Idle : fsm::simple_state&lt; Idle, NotShooting,
<b>fsm::custom_reaction&lt; EvConfig &gt;</b> &gt;
{
// ...
<b>fsm::result react( const EvConfig &amp; );</b>
};
#endif</pre>
<p>Please note the bold parts in the code. With a custom reaction we only
specify that we <b>might</b> do something with a particular event, but the
actual reaction is defined in the <code>react</code> member function, which
can be implemented in the .cpp file.</p>
<p>Camera.cpp:</p>
<pre>#include &quot;Camera.hpp&quot;
#include &quot;Configuring.hpp&quot;
#include &quot;Shooting.hpp&quot;
// ...
// not part of the Camera example
fsm::result NotShooting::react( const EvShutterHalf &amp; )
{
return transit&lt; Shooting &gt;();
}
fsm::result Idle::react( const EvConfig &amp; )
{
return transit&lt; Configuring &gt;();
}</pre>
<p>Note that Shooting.hpp and Configuring.hpp are included only in Camera.cpp
but not in Camera.hpp. The Shooting and Configuring states can themselves
apply the same pattern to hide their inner implementation, which ensures that
the two teams working on the Camera state machine will never need to disturb
each other.</p>
<p><b><font color="#FF0000">Caution: Any call to <code>simple_state&lt;&gt;::transit&lt;&gt;()</code>
or <code>simple_state&lt;&gt;::terminate()</code> (see
<a href="reference.html#transit1">reference</a>) will inevitably destruct the
state object (similar to <code>delete this;</code>)! That is, code executed
after any of these calls may invoke undefined behavior!</font></b> That's why
these functions should only be called as part of a return statement.</p>
<h3><a name="Deferring events">Deferring events</a></h3>
<p>The inner workings of the Shooting state could look as follows:</p>
<p><img border="0" src="Camera2.gif" width="427" height="427"></p>
<p>When the user half-presses the shutter, Shooting and its inner initial
state Focusing are entered. In the Focusing entry action the camera instructs
the focusing circuit to bring the subject into focus. The focusing circuit
then moves the lenses accordingly and sends the EvInFocus event as soon as it
is done. Of course, the user can fully-press the shutter while the lenses are
still in motion. Without any precautions, the resulting EvShutterFull event
would simply be lost because the Focusing state does not define a reaction for
this event. As a result, the user would have to fully-press the shutter again
after the camera has finished focusing. To prevent this, the EvShutterFull
event is deferred inside the Focusing state. This means that all events of
this type are stored in a separate queue, which is emptied into the main queue
when the Focusing state is exited.</p>
<pre>struct Focusing : fsm::state&lt; Focusing, Shooting, mpl::list&lt;
fsm::custom_reaction&lt; EvInFocus &gt;,
<b>fsm::deferral&lt; EvShutterFull &gt;</b> &gt; &gt;
{
Focusing( my_context ctx );
fsm::result react( const EvInFocus &amp; );
};</pre>
<p>To avoid a number of overheads, event deferral has one limitation: Only
events allocated with <code>new</code> <b>and</b> pointed to by a <code>
boost::intrusive_ptr&lt;&gt;</code> can be deferred. Any attempt to defer a
differently allocated event will result in a failing runtime assert. Example:</p>
<pre>struct Event : fsm::event&lt; Event &gt; {};
struct Initial;
struct Machine : fsm::state_machine&lt;
Machine, Initial &gt; {};
struct Initial : fsm::simple_state&lt; Initial, Machine,
fsm::deferral&lt; Event &gt; &gt; {};
int main()
{
Machine myMachine;
myMachine.initiate();
myMachine.process_event( Event() ); // error
myMachine.process_event(
*boost::shared_ptr&lt; Event &gt;( new Event() ) ); // error
myMachine.process_event(
*<b>boost::intrusive_ptr&lt; Event &gt;( new Event() )</b> ); // fine
return 0;
}</pre>
<h3><a name="Guards">Guards</a></h3>
<p>Both transitions originating at the Focused state are triggered by the same
event but they have mutually exclusive guards. Here is an appropriate custom
reaction:</p>
<pre>// not part of the Camera example
fsm::result Focused::react( const EvShutterFull &amp; )
{
if ( context&lt; Camera &gt;().IsMemoryAvailable() )
{
return transit&lt; Storing &gt;();
}
else
{
// The following is actually a mixture between an in-state
// reaction and a transition. See later on how to implement
// proper transition actions.
std::cout &lt;&lt; &quot;Cache memory full. Please wait...\n&quot;;
return transit&lt; Focused &gt;();
}
}</pre>
<p>Custom reactions can of course also be implemented directly in the state
declaration, which is often preferable for easier browsing.</p>
<p>Next we will use a guard to prevent a transition and let outer states react
to the event if the battery is low:</p>
<p>Camera.cpp:</p>
<pre>// ...
fsm::result NotShooting::react( const EvShutterHalf &amp; )
{
if ( context&lt; Camera &gt;().IsBatteryLow() )
{
// We cannot react to the event ourselves, so we forward it
// to our outer state (this is also the default if a state
// defines no reaction for a given event).
<b>return forward_event();</b>
}
else
{
return transit&lt; Shooting &gt;();
}
}
// ...</pre>
<h3><a name="In-state reactions">In-state reactions</a></h3>
<p>The self-transition of the Focused state could also be implemented as an
<a href="definitions.html#In-state reaction">in-state reaction</a>, which has
the same effect as long as Focused does not have any entry or exit actions:</p>
<p>Shooting.cpp:</p>
<pre>// ...
fsm::result Focused::react( const EvShutterFull &amp; )
{
if ( context&lt; Camera &gt;().IsMemoryAvailable() )
{
return transit&lt; Storing &gt;();
}
else
{
std::cout &lt;&lt; &quot;Cache memory full. Please wait...\n&quot;;
// Indicate that the event can be discarded. So, the
// dispatch algorithm will stop looking for a reaction
// and the machine remains in the Focused state.
<b>return discard_event();</b>
}
}
// ...</pre>
<h3><a name="Transition actions">Transition actions</a></h3>
<p>As an effect of every transition, actions are executed in the following
order:</p>
<ol>
<li>Starting from the innermost active state, all exit actions up to but
excluding the <a href="definitions.html#Innermost common outer state">
innermost common outer state</a>.</li>
<li>The transition action (if present).</li>
<li>Starting from the innermost common outer state, all entry actions down
to the target state followed by the entry actions of the initial states.</li>
</ol>
<p>Example:</p>
<p><img border="0" src="LCA.gif" width="604" height="304"></p>
<p>Here the order is as follows: ~D(), ~C(), ~B(), ~A(), t(), X(), Y(), Z().
The transition action t() is therefore executed in the context of the
InnermostCommonOuter state because the source state has already been left
(destructed) and the target state has not yet been entered (constructed).</p>
<p>With boost::fsm, a transition action can be a member of <b>any</b> common
outer context. That is, the transition between Focusing and Focused could be
implemented as follows:</p>
<p>Shooting.hpp:</p>
<pre>// ...
struct Focusing;
struct Shooting : fsm::simple_state&lt; Shooting, Camera,
fsm::transition&lt; EvShutterRelease, NotShooting &gt;, Focusing &gt;
{
// ...
<b>void DisplayFocused( const EvInFocus &amp; );</b>
};
// ...
// not part of the Camera example
struct Focusing : fsm::simple_state&lt; Focusing, Shooting,
fsm::transition&lt; EvInFocus, Focused<b>,</b>
<b>Shooting, &amp;Shooting::DisplayFocused</b> &gt; &gt; {};</pre>
<p><b>Or</b>, the following is also possible (here the state machine itself
serves as the outermost context):</p>
<pre>// not part of the Camera example
struct Camera : fsm::state_machine&lt; Camera, NotShooting &gt;
{
<b>void DisplayFocused( const EvInFocus &amp; );</b>
};</pre>
<pre>// not part of the Camera example
struct Focusing : fsm::simple_state&lt; Focusing, Shooting,
fsm::transition&lt; EvInFocus, Focused<b>,</b>
<b>Camera, &amp;Camera::DisplayFocused</b> &gt; &gt; {};</pre>
<p>Naturally, transition actions can also be invoked from custom reactions:</p>
<p>Shooting.cpp:</p>
<pre>// ...
fsm::result Focusing::react( const EvInFocus &amp; evt )
{
return transit&lt; Focused &gt;( <b>&amp;Shooting::DisplayFocused</b>, evt );
}</pre>
<p>Please note that we have to manually forward the event.</p>
<h2><a name="Advanced topics">Advanced topics</a></h2>
<h3><a name="Specifying multiple reactions for a state">Specifying multiple
reactions for a state</a></h3>
<p>Often a state must define reactions for more than one event. In this case,
an <code>mpl::list&lt;&gt;</code> must be used as outlined below:</p>
<pre>// ...
<b>#include &lt;boost/mpl/list.hpp&gt;
</b>
<b>namespace mpl = boost::mpl;
</b>
// ...
struct Playing : fsm::simple_state&lt; Playing, Mp3Player,
<b>mpl::list&lt;</b>
fsm::custom_reaction&lt; EvFastForward &gt;,
fsm::transition&lt; EvStop, Stopped &gt; <b>&gt;</b> &gt; { /* ... */ };</pre>
<h3><a name="Posting events">Posting events</a></h3>
<p>Non-trivial state machines often need to post internal events. Here's an
example of how to do this: </p>
<pre>Pumping::~Pumping()
{
post_event( boost::intrusive_ptr&lt; EvPumpingFinished &gt;(
new EvPumpingFinished() ) );
}</pre>
<p>The event is pushed into the main queue, which is why it must be allocated
with <code>new</code>. The events in the queue are processed as soon as the
current reaction is completed. Events can be posted from inside <code>react</code>
functions, entry-, exit- and transition actions. However, posting from inside
entry actions is a bit more complicated (see e.g. <code>Focusing::Focusing()</code>
in <code>Shooting.cpp</code> in the Camera example): </p>
<pre>struct Pumping : <b>fsm::state</b>&lt; Pumping, Purifier &gt;
{
<b>Pumping( my_context ctx ) : my_base( ctx )</b>
{
post_event( boost::intrusive_ptr&lt; EvPumpingStarted &gt;(
new EvPumpingStarted() ) );
}
// ...
};</pre>
<p>Please note the bold parts. As soon as an entry action of a state needs to
contact the &quot;outside world&quot; (here: the event queue in the state machine), the
state must derive from <code>state&lt;&gt;</code> rather than from <code>
simple_state&lt;&gt;</code> and must implement a forwarding constructor as outlined
above (apart from the constructor, <code>state&lt;&gt;</code> offers the same
interface as <code>simple_state&lt;&gt;</code>). Hence, this must be done whenever
an entry action makes one or more calls to the following functions:</p>
<ul>
<li><code>simple_state&lt;&gt;::post_event()</code></li>
<li><code>simple_state&lt;&gt;::clear_shallow_history&lt;&gt;()</code></li>
<li><code>simple_state&lt;&gt;::clear_deep_history&lt;&gt;()</code></li>
<li><code>simple_state&lt;&gt;::outermost_context()</code></li>
<li><code>simple_state&lt;&gt;::context&lt;&gt;()</code></li>
<li><code>simple_state&lt;&gt;::state_cast&lt;&gt;()</code></li>
<li><code>simple_state&lt;&gt;::state_downcast&lt;&gt;()</code></li>
<li><code>simple_state&lt;&gt;::state_begin()</code></li>
<li><code>simple_state&lt;&gt;::state_end()</code></li>
</ul>
<p>In my experience, these functions are needed only rarely in entry actions
so this workaround should not uglify user code too much.</p>
<h3><a name="History">History</a></h3>
<p>Photographers testing beta versions of our
<a href="#Spreading a state machine over multiple translation units">digital
camera</a> said that they really liked that half-pressing the shutter anytime
(even while the camera is being configured) immediately readies the camera for
picture-taking. However, most of them found it unintuitive that the camera
always goes into the idle mode after releasing the shutter. They would rather
see the camera go back into the state it had before half-pressing the shutter.
This way they can easily test the influence of a configuration setting by
modifying it, half- and then fully-pressing the shutter to take a picture.
Finally, releasing the shutter will bring them back to the screen where they
have modified the setting. To implement this behavior we'd change the state
chart as follows:</p>
<p><img border="0" src="CameraWithHistory1.gif" width="542" height="378"></p>
<p>As mentioned earlier, the Configuring state contains a fairly complex and
deeply nested inner machine. Naturally, we'd like to restore the previous
state down to the <a href="definitions.html#Innermost state">innermost state</a>(s)
in Configuring, that's why we use a deep history pseudo state. The associated
code looks as follows:</p>
<pre>// not part of the Camera example
struct NotShooting : fsm::simple_state&lt; NotShooting, Camera,
/* ... */, Idle, <b>fsm::has_deep_history</b> &gt; //
{
// ...
};
// ...
struct Shooting : fsm::simple_state&lt; Shooting, Camera,
fsm::transition&lt; EvShutterRelease,
<b>fsm::deep_history&lt; Idle &gt;</b> &gt;, Focusing &gt;
{
// ...
};
</pre>
<p>History has two phases: Firstly, when the state containing the history
pseudo state is exited, information about the previously active inner state
hierarchy must be saved. Secondly, when a transition to the history pseudo
state is made later, the saved state hierarchy information must be retrieved
and the appropriate states entered. The former is expressed by passing either
<code>has_shallow_history</code>, <code>has_deep_history</code> or <code>
has_full_history</code> (which combines shallow and deep history) as the last
parameter to the <code>simple_state</code> and <code>state</code> class
templates. The latter is expressed by specifying either <code>shallow_history&lt;&gt;</code>
or <code>deep_history&lt;&gt;</code> as a transition destination or, as we'll see in
an instant, as an inner initial state. Because it is possible that a state
containing a history pseudo state has never been entered before a transition
to history is made, both class templates demand a parameter specifying the
default state to enter in such situations.</p>
<p>The redundancy necessary for using history is checked for consistency at
compile time. That is, the state machine wouldn't have compiled had we
forgotten to pass <code>has_deep_history</code> to the base of <code>
NotShooting</code>.</p>
<p>Another change request filed by a few beta testers says that they would
like to see the camera go back into the state it had before turning it off
when they turn it back on. Here's the implementation:</p>
<p><img border="0" src="CameraWithHistory2.gif" width="468" height="483"></p>
<pre>// ...
// not part of the Camera example
struct NotShooting : fsm::simple_state&lt; NotShooting, Camera,
/* ... */, <b>mpl::list&lt; fsm::deep_history&lt; Idle &gt; &gt;</b>,
<b>fsm::has_deep_history</b> &gt;
{
// ...
};
// ...</pre>
<p>Unfortunately, there is a small inconvenience due to some template-related
implementation details. When the inner initial state is a class template
instantiation we always have to put it into an <code>mpl::list&lt;&gt;</code>,
although there is only one inner initial state. Moreover, the current deep
history implementation has some <a href="rationale.html#Limitations">
limitations</a>.</p>
<h3><a name="Orthogonal states">Orthogonal states</a></h3>
<p><img border="0" src="OrthogonalStates.gif" width="633" height="393"></p>
<p>To implement this state chart you simply specify more than one inner
initial state (see the Keyboard example):</p>
<pre>struct Active;
struct Keyboard : fsm::state_machine&lt; Keyboard, Active &gt; {};
struct NumLockOff;
struct CapsLockOff;
struct ScrollLockOff;
struct Active: fsm::simple_state&lt;
Active, Keyboard, fsm::no_reactions,
<b>mpl::list&lt; NumLockOff, CapsLockOff, ScrollLockOff &gt;</b> &gt; {};</pre>
<p>Active's inner states must declare which orthogonal region they belong to:</p>
<pre>struct EvNumLockPressed : fsm::event&lt; EvNumLockPressed &gt; {};
struct EvCapsLockPressed : fsm::event&lt; EvCapsLockPressed &gt; {};
struct EvScrollLockPressed :
fsm::event&lt; EvScrollLockPressed &gt; {};
struct NumLockOn : fsm::simple_state&lt;
NumLockOn, Active<b>::orthogonal&lt; 0 &gt;</b>,
fsm::transition&lt; EvNumLockPressed, NumLockOff &gt; &gt; {};
struct NumLockOff : fsm::simple_state&lt;
NumLockOff, Active<b>::orthogonal&lt; 0 &gt;</b>,
fsm::transition&lt; EvNumLockPressed, NumLockOn &gt; &gt; {};
struct CapsLockOn : fsm::simple_state&lt;
CapsLockOn, Active<b>::orthogonal&lt; 1 &gt;</b>,
fsm::transition&lt; EvCapsLockPressed, CapsLockOff &gt; &gt; {};
struct CapsLockOff : fsm::simple_state&lt;
CapsLockOff, Active<b>::orthogonal&lt; 1 &gt;</b>,
fsm::transition&lt; EvCapsLockPressed, CapsLockOn &gt; &gt; {};
struct ScrollLockOn : fsm::simple_state&lt;
ScrollLockOn, Active<b>::orthogonal&lt; 2 &gt;</b>,
fsm::transition&lt; EvScrollLockPressed, ScrollLockOff &gt; &gt; {};
struct ScrollLockOff : fsm::simple_state&lt;
ScrollLockOff, Active<b>::orthogonal&lt; 2 &gt;</b>,
fsm::transition&lt; EvScrollLockPressed, ScrollLockOn &gt; &gt; {};</pre>
<p><code>orthogonal&lt; 0 &gt;</code> is the default, so <code>NumLockOn</code> and
<code>NumLockOff</code> could just as well pass <code>Active</code> instead of
<code>Active::orthogonal&lt; 0 &gt;</code> to specify their context. The numbers
passed to the <code>orthogonal</code> member template must correspond to the
list position in the outer state. Moreover, the orthogonal position of the
source state of a transition must correspond to the orthogonal position of the
target state. Any violations of these rules lead to compile time errors.
Examples:</p>
<pre>// Example 1: does not compile because Active specifies
// only 3 orthogonal regions
struct WhateverLockOn: fsm::simple_state&lt;
WhateverLockOn, Active<b>::</b>orthogonal&lt; <b>3</b> &gt; &gt; {};
// Example 2: does not compile because Active specifies
// that NumLockOff is part of the &quot;0th&quot; orthogonal region
struct NumLockOff : fsm::simple_state&lt;
NumLockOff, Active<b>::</b>orthogonal&lt; <b>1</b> &gt; &gt; {};
// Example 3: does not compile because a transition between
// different orthogonal regions is not permitted
struct CapsLockOn : fsm::simple_state&lt;
CapsLockOn, Active<b>::</b>orthogonal&lt; <b>1</b> &gt;,
fsm::transition&lt; EvCapsLockPressed, CapsLockOff &gt; &gt; {};
struct CapsLockOff : fsm::simple_state&lt;
CapsLockOff, Active<b>::</b>orthogonal&lt; <b>2</b> &gt;,
fsm::transition&lt; EvCapsLockPressed, CapsLockOn &gt; &gt; {};</pre>
<h3><a name="State queries">State queries</a></h3>
<p>Often reactions in a state machine depend on the active state in one or
more orthogonal regions. This is because orthogonal regions are not completely
orthogonal or a certain reaction in an outer state can only take place if the
inner orthogonal regions are in particular states. For this purpose, the <code>
state_cast&lt;&gt;</code> function introduced under
<a href="#Getting state information out of the machine">Getting state
information out of the machine</a> is also available within states.</p>
<p>As a somewhat far-fetched example, let's assume that our
<a href="#Orthogonal states">keyboard</a> also accepts <code>EvRequestShutdown</code>
events, the reception of which makes the keyboard terminate only if all lock
keys are in the off state. We would then modify the Keyboard state machine as
follows: </p>
<pre>struct EvRequestShutdown : fsm::event&lt; EvRequestShutdown &gt; {};
struct NumLockOff;
struct CapsLockOff;
struct ScrollLockOff;
struct Active: fsm::simple_state&lt;
Active, Keyboard, fsm::custom_reaction&lt; EvRequestShutdown &gt;,
mpl::list&lt; NumLockOff, CapsLockOff, ScrollLockOff &gt; &gt;
{
fsm::result react( const EvRequestShutdown &amp; )
{
if ( ( state_downcast&lt; const NumLockOff * &gt;() != 0 ) &amp;&amp;
( state_downcast&lt; const CapsLockOff * &gt;() != 0 ) &amp;&amp;
( state_downcast&lt; const ScrollLockOff * &gt;() != 0 ) )
{
return terminate();
}
else
{
return discard_event();
}
}
};</pre>
<p>Passing a pointer type instead of reference type results in 0 pointers
being returned instead of <code>std::bad_cast</code> being thrown when the
cast fails. Note also the use of <code>state_downcast&lt;&gt;()</code> instead of
<code>state_cast&lt;&gt;()</code>. Similar to the differences between <code>
boost::polymorphic_downcast&lt;&gt;()</code> and <code>dynamic_cast</code>, <code>
state_downcast&lt;&gt;()</code> is a much faster variant of <code>state_cast&lt;&gt;()</code>
and can only be used when the passed type is a most-derived type. <code>
state_cast&lt;&gt;()</code> should only be used if you want to query an additional
base.</p>
<h4>Custom state queries</h4>
<p>It is often desirable to find out exactly which state(s) a machine
currently resides in. To some extent this is already possible with <code>
state_cast&lt;&gt;()</code> and <code>state_downcast&lt;&gt;()</code> but their utility is
rather limited because both only return a yes/no answer to the question &quot;Are
you in state X?&quot;. It is possible to ask more sophisticated questions when you
pass an additional base class rather than a state class to <code>state_cast&lt;&gt;()</code>
but this involves more work (all states need to derive from and implement the
additional base), is slow (under the hood <code>state_cast&lt;&gt;()</code> uses
<code>dynamic_cast</code>), forces projects to compile with C++ RTTI turned on
and has a negative impact on state entry/exit speed.</p>
<p>Especially for debugging it would be so much more useful being able to ask
&quot;In which state(s) are you?&quot;. For this purpose it is possible to iterate over
all active <b>innermost</b> states with <code>state_machine&lt;&gt;::state_begin()</code>
and <code>state_machine&lt;&gt;::state_end()</code>. Dereferencing the returned
iterator returns a reference to <code>const state_machine&lt;&gt;::state_base_type</code>,
the common base of all states. We can thus print the currently active state
configuration as follows (see the Keyboard example for the complete code):</p>
<pre>void DisplayStateConfiguration( const Keyboard &amp; kbd )
{
char region = 'a';
for (
Keyboard::state_iterator pLeafState = kbd.state_begin();
pLeafState != kbd.state_end(); ++pLeafState )
{
std::cout &lt;&lt; &quot;Orthogonal region &quot; &lt;&lt; region &lt;&lt; &quot;: &quot;;
std::cout &lt;&lt; typeid( *pLeafState ).name() &lt;&lt; &quot;\n&quot;;
++region;
}
}</pre>
<p>If necessary, the outer states can be accessed with <code>state_machine&lt;&gt;::state_base_type::outer_state_ptr()</code>,
which returns a pointer to <code>const state_machine&lt;&gt;::state_base_type</code>.
When called on an outermost state this function simply returns 0.</p>
<h3><a name="State type information">State type information</a></h3>
<p>To cut down on executable size some applications must be compiled with C++
RTTI turned off. This would render the ability to iterate over all active
states pretty much useless if it weren't for the following two functions:</p>
<ul>
<li><code>static <i>unspecified_type</i> simple_state&lt;&gt;::static_type()</code></li>
<li><code><i>unspecified_type<br>
</i>&nbsp; state_machine&lt;&gt;::state_base_type::dynamic_type() const</code></li>
</ul>
<p>Both return a value that is comparable via <code>operator==()</code> and
<code>std::less&lt;&gt;</code>. This alone would be enough to implement the <code>
DisplayStateConfiguration</code> function above without the help of <code>
typeid</code> but it is still somewhat cumbersome as a map must be used to
associate the type information values with the state names.</p>
<h4><a name="Custom state type information">Custom state type information</a></h4>
<p>That's why the following functions are also provided (only available when
<a href="configuration.html#Application Defined Macros">
BOOST_FSM_USE_NATIVE_RTTI</a> is <b>not</b> defined):</p>
<ul>
<li><code>template&lt; class T &gt;<br>
static void simple_state&lt;&gt;::custom_static_type_ptr( const T * );</code></li>
<li><code>template&lt; class T &gt;<br>
static const T * simple_state&lt;&gt;::custom_static_type_ptr();</code></li>
<li><code>template&lt; class T &gt;<br>
const T * state_machine&lt;&gt;::<br>
&nbsp; state_base_type::custom_dynamic_type_ptr() const;</code></li>
</ul>
<p>These allow us to directly associate arbitrary state type information with
each state ...</p>
<pre>// ...
int main()
{
NumLockOn::custom_static_type_ptr( &quot;NumLockOn&quot; );
NumLockOff::custom_static_type_ptr( &quot;NumLockOff&quot; );
CapsLockOn::custom_static_type_ptr( &quot;CapsLockOn&quot; );
CapsLockOff::custom_static_type_ptr( &quot;CapsLockOff&quot; );
ScrollLockOn::custom_static_type_ptr( &quot;ScrollLockOn&quot; );
ScrollLockOff::custom_static_type_ptr( &quot;ScrollLockOff&quot; );
// ...
}</pre>
<p>... and rewrite the display function as follows:</p>
<pre>void DisplayStateConfiguration( const Keyboard &amp; kbd )
{
char region = 'a';
for (
Keyboard::state_iterator pLeafState = kbd.state_begin();
pLeafState != kbd.state_end(); ++pLeafState )
{
std::cout &lt;&lt; &quot;Orthogonal region &quot; &lt;&lt; region &lt;&lt; &quot;: &quot;;
std::cout &lt;&lt;
pLeafState-&gt;custom_dynamic_type_ptr&lt; char &gt;() &lt;&lt; &quot;\n&quot;;
++region;
}
}</pre>
<h3><a name="Exception handling">Exception handling</a></h3>
<p>Exceptions can be propagated from all user code except from state exit
actions (mapped to destructors and destructors should virtually never throw in
C++). Out of the box, <code>state_machine&lt;&gt;</code> does the following:</p>
<ol>
<li>The exception is caught.</li>
<li>In the catch block, an <code>exception_thrown</code> event is allocated
on the stack.</li>
<li>Also in the catch block, an <b>immediate</b> dispatch of the <code>
exception_thrown</code> event is attempted. That is, possibly remaining
events in the queue are dispatched only after the exception has been handled
successfully.</li>
<li>If the exception was handled successfully, the state machine returns to
the client normally. If the exception could not be handled successfully, the
original exception is rethrown so that the client of the state machine can
handle the exception.</li>
</ol>
<p>This behavior is implemented in the <code>exception_translator</code> class
template, which is the default for the <code>ExceptionTranslator</code>
parameter of the <code>state_machine</code> class template. It was introduced
because users would want to change this on some platforms to work around buggy
exception handling implementations (see <a href="#Discriminating exceptions">
Discriminating exceptions</a>).</p>
<p>boost::fsm can also be used in applications compiled with C++ exception
handling turned off but doing so means losing <b>all</b> error handling
support, making proper error handling much more cumbersome (see
<a href="rationale.html#Error handling">Error handling</a> in the Rationale).</p>
<h4>Which states can react to an <code>exception_thrown</code> event?</h4>
<p>This depends on where the exception occurred. There are three scenarios:</p>
<ol>
<li>A <code>react</code> member function propagates an exception <b>before</b>
calling any of the reaction functions. The state that caused the exception
is first tried for a reaction, so the following machine will transit to
Defective after receiving an EvStart event:<br>
<br>
<img border="0" src="ThrowingInStateReaction.gif" width="362" height="182"><br>
<br>
</li>
<li>A state entry action (constructor) propagates an exception. The outer
state of the state that caused the exception is first tried for a reaction,
so the following machine will transit to Defective after trying to enter
Stopped:<br>
<br>
<img border="0" src="ThrowingEntryAction.gif" width="438" height="241"><br>
&nbsp;</li>
<li>A transition action propagates an exception. The innermost common outer
state of the source and the target state is first tried for a reaction, so
the following machine will transit to Defective after receiving an
EvStartStop event:<br>
<br>
<img border="0" src="ThrowingTransitionAction.gif" width="422" height="362"></li>
</ol>
<p>As with a normal event, the dispatch algorithm will move outward to find a
reaction if the first tried state does not provide one (or if the reaction
explicitly returned <code>forward_event();</code>). However, <b>in contrast to
normal events, it will give up once it has unsuccessfully tried an outermost
state</b>, so the following machine will <b>not</b> transit to Defective after
receiving an EvNumLockPressed event:</p>
<p>
<img border="0" src="ExceptionsAndOrthogonalStates.gif" width="571" height="331"></p>
<p>Instead, the machine is terminated and the original exception rethrown.</p>
<h4>Successful exception handling</h4>
<p>An exception is considered handled successfully, if:</p>
<ul>
<li>an appropriate reaction for the <code>exception_thrown</code> event has
been found, <b>and</b></li>
<li>the state machine is in a stable state after the reaction has completed.</li>
</ul>
<p>The second condition is important for scenarios 2 and 3 in the last
section. In these scenarios, the state machine is in the middle of a
transition when the exception is handled. The machine would be left in an
invalid state, should the reaction simply discard the event without doing
anything else.</p>
<p>The out of the box behavior for unsuccessful exception handling is to
rethrow the original exception. The state machine is terminated before the
exception is propagated to the machine client.</p>
<h4><a name="Discriminating exceptions">Discriminating exceptions</a></h4>
<p>Because the <code>exception_thrown</code> object is dispatched from within
the catch block, we can rethrow and catch the exception in a custom reaction:</p>
<pre>struct Defective : fsm::simple_state&lt;
Defective, Purifier &gt; {};
// Pretend this is a state deeply nested in the Purifier
// state machine
struct Idle : fsm::simple_state&lt; Idle, Purifier,
mpl::list&lt;
fsm::custom_reaction&lt; EvStart &gt;,
fsm::custom_reaction&lt; fsm::exception_thrown &gt; &gt; &gt;
{
fsm::result react( const EvStart &amp; )
{
throw std::runtime_error( &quot;&quot; );
}
fsm::result react( const fsm::exception_thrown &amp; )
{
try
{
<b>throw;</b>
}
catch ( const std::runtime_error &amp; )
{
// only std::runtime_errors will lead to a transition
// to Defective ...
return transit&lt; Defective &gt;();
}
catch ( ... )
{
// ... all other exceptions are forwarded to our outer
// state(s). The state machine is terminated and the
// exception rethrown if the outer state(s) can't
// handle it either...
return forward_event();
}
// Alternatively, if we want to terminate the machine
// immediately, we can also either rethrow or throw
// a different exception.
}
};</pre>
<p><b>Unfortunately, this idiom (using <code>throw;</code> inside a <code>try</code>
block nested inside a <code>catch</code> block) does not work on at least one
very popular compiler.</b> If you have to use one of these platforms, you can
pass a customized exception translator class to the <code>state_machine</code>
class template. This will allow you to generate different events depending on
the type of the exception.</p>
<h3><a name="Submachines &amp; parameterized states">Submachines &amp;
parameterized states</a></h3>
<p>Submachines are to event-driven programming what functions are to
procedural programming, reusable building blocks implementing often needed
functionality. The associated UML notation is not entirely clear to me. It
seems to be severely limited (e.g. the same submachine cannot appear in
different orthogonal regions) and does not seem to account for obvious stuff
like e.g. parameters.</p>
<p>boost::fsm is completely unaware of submachines but they can be implemented
quite nicely with templates. Here, a submachine is used to improve the
copy-paste implementation of the keyboard machine discussed under
<a href="#Orthogonal states">Orthogonal states</a>:</p>
<pre>enum LockType
{
NUM_LOCK,
CAPS_LOCK,
SCROLL_LOCK
};
template&lt; LockType lockType &gt;
struct Off;
struct Active : fsm::simple_state&lt;
Active, Keyboard, fsm::no_reactions, mpl::list&lt;
Off&lt; NUM_LOCK &gt;, Off&lt; CAPS_LOCK &gt;, Off&lt; SCROLL_LOCK &gt; &gt; &gt; {};
template&lt; LockType lockType &gt;
struct EvPressed : fsm::event&lt; EvPressed&lt; lockType &gt; &gt; {};
template&lt; LockType lockType &gt;
struct On : fsm::simple_state&lt;
On&lt; lockType &gt;, Active::orthogonal&lt; lockType &gt;,
fsm::transition&lt; EvPressed&lt; lockType &gt;, Off&lt; lockType &gt; &gt; &gt; {};
template&lt; LockType lockType &gt;
struct Off : fsm::simple_state&lt;
Off&lt; lockType &gt;, Active::orthogonal&lt; lockType &gt;,
fsm::transition&lt; EvPressed&lt; lockType &gt;, On&lt; lockType &gt; &gt; &gt; {};</pre>
<h3><a name="Asynchronous state machines">Asynchronous state machines</a></h3>
<h4>Why asynchronous state machines are necessary</h4>
<p>As the name suggests, a synchronous state machine processes each event
synchronously. This behavior is implemented by the <code>state_machine</code>
class template, whose <code>process_event</code> function only returns after
having executed all reactions (including the ones provoked by internal events
that actions might have posted). This function is strictly non-reentrant (just
like all other member functions, so <code>state_machine&lt;&gt;</code> is not
thread-safe). This makes it difficult for two <code>state_machine&lt;&gt;</code>
subclasses to communicate via events in a bi-directional fashion correctly, <b>
even in a single-threaded program</b>. For example, state machine <code>A</code>
is in the middle of processing an external event. Inside an action, it decides
to send a new event to state machine <code>B</code> (by calling <code>
B::process_event()</code>). It then &quot;waits&quot; for B to send back an answer via a
<code>boost::function&lt;&gt;</code>-like call-back, which references <code>
A::process_event()</code> and was passed as a data member of the event.
However, while <code>A</code> is &quot;waiting&quot; for <code>B</code> to send back an
event, <code>A::process_event()</code> has not yet returned from processing
the external event and as soon as <code>B</code> answers via the call-back,
<code>A::process_event()</code> is <b>unavoidably</b> reentered. This all
really happens in a single thread, that's why &quot;wait&quot; is in quotes.</p>
<h4>How it works</h4>
<p>The <code>asynchronous_state_machine</code> class template has none of the
member functions the <code>state_machine</code> class template has. Moreover,
<code>asynchronous_state_machine&lt;&gt;</code> subclass objects cannot even be
created or destroyed directly. Instead, all these operations must be performed
through the <code>Scheduler</code> object each asynchronous state machine is
associated with. All these <code>Scheduler</code> member functions only push
an appropriate item into the schedulers' queue and then return immediately. A
dedicated thread will later pop the items out of the queue to have them
processed.</p>
<p>Applications will usually first create a <code>fifo_scheduler&lt;&gt;</code>
object and then call <code>fifo_scheduler&lt;&gt;::create_processor&lt;&gt;()</code> and
<code>fifo_scheduler&lt;&gt;::initiate_processor()</code> to schedule the creation
and initiation of one or more <code>asynchronous_state_machine&lt;&gt;</code>
subclass objects. Finally, <code>fifo_scheduler&lt;&gt;::operator()()</code> is
either called directly to let the machine(s) run in the current thread, or, a
<code>boost::function&lt;&gt;</code> object referencing <code>operator()()</code> is
passed to a new <code>boost::thread</code>. Alternatively, the latter could
also be done right after constructing the <code>fifo_scheduler&lt;&gt;</code>
object. In the following code, we are running one state machine in a new <code>
boost::thread</code> and the other in the main thread (see the PingPong
example for the full source code):</p>
<pre>struct Waiting;
struct Player :
fsm::asynchronous_state_machine&lt; Player, Waiting &gt;
{
// ...
};
// ...
int main()
{
// Create two schedulers that will wait for new events
// when their event queue runs empty
fsm::fifo_scheduler&lt;&gt; scheduler1( true );
fsm::fifo_scheduler&lt;&gt; scheduler2( true );
// Each player is serviced by its own scheduler
fsm::fifo_scheduler&lt;&gt;::processor_handle player1 =
scheduler1.create_processor&lt; Player &gt;( /* ... */ );
scheduler1.initiate_processor( player1 );
fsm::fifo_scheduler&lt;&gt;::processor_handle player2 =
scheduler2.create_processor&lt; Player &gt;( /* ... */ );
scheduler2.initiate_processor( player2 );
// the initial event that will start the game
boost::intrusive_ptr&lt; BallReturned &gt; pInitialBall =
new BallReturned();
// ...
scheduler2.queue_event( player2, pInitialBall );
// ...
// Up until here no state machines exist yet. They
// will be created when operator()() is called
// Run first scheduler in a new thread
boost::thread otherThread( boost::bind(
&amp;fsm::fifo_scheduler&lt;&gt;::operator(), &amp;scheduler1, 0 ) );
scheduler2(); // Run second scheduler in this thread
otherThread.join();
return 0;
}</pre>
<p>We could just as well use two boost::threads:</p>
<pre>int main()
{
// ...
boost::thread thread1(
boost::bind( &amp;fsm::fifo_scheduler&lt;&gt;::operator(), &amp;scheduler1, 0 ) );
boost::thread thread2(
boost::bind( &amp;fsm::fifo_scheduler&lt;&gt;::operator(), &amp;scheduler2, 0 ) );
// do something else ...
thread1.join();
thread2.join();
return 0;
}</pre>
<p>Or, run both machines in the same thread:</p>
<pre>int main()
{
fsm::fifo_scheduler&lt;&gt; scheduler1( true );
fsm::fifo_scheduler&lt;&gt;::processor_handle player1 =
scheduler1.create_processor&lt; Player &gt;( /* ... */ );
fsm::fifo_scheduler&lt;&gt;::processor_handle player2 =
scheduler1.create_processor&lt; Player &gt;( /* ... */ );
// ...
scheduler1();
return 0;
}</pre>
<p>In all the examples above, <code>fifo_scheduler&lt;&gt;::operator()()</code>
waits on an empty event queue and will only return after a call to <code>
fifo_scheduler&lt;&gt;::terminate()</code>. The <code>Player</code> state machine
calls this function on its scheduler object right before terminating.</p>
<hr>
<p>Revised
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->21 April, 2004<!--webbot bot="Timestamp" endspan i-checksum="29904" --></p>
<p><i>Copyright <20> <a href="mailto:ah2003@gmx.net">Andreas Huber D<>nni</a>
2003-2004. Use, modification and distribution are subject to the Boost
Software License, Version 1.0. (See accompanying file
<a href="../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at
<a href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)</i></p>
</body>
</html>