1<html><head> 2 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> 3 <title>Back-end</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM)"><link rel="up" href="ch03.html" title="Chapter 3. Tutorial"><link rel="prev" href="ch03s04.html" title="eUML"><link rel="next" href="ch04.html" title="Chapter 4. Performance / Compilers"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Back-end</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s04.html">Prev</a> </td><th width="60%" align="center">Chapter 3. Tutorial</th><td width="20%" align="right"> <a accesskey="n" href="ch04.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Back-end"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e2298"></a>Back-end</h2></div></div></div><p>There is, at the moment, one back-end. This back-end contains the library 4 engine and defines the performance and functionality trade-offs. The currently 5 available back-end implements most of the functionality defined by the UML 2.0 6 standard at very high runtime speed, in exchange for longer compile-time. The 7 runtime speed is due to a constant-time double-dispatch and self-adapting 8 capabilities allowing the framework to adapt itself to the features used by a 9 given concrete state machine. All unneeded features either disable themselves or 10 can be manually disabled. See section 5.1 for a complete description of the 11 run-to-completion algorithm.</p><div class="sect2" title="Creation"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2303"></a>Creation </h3></div></div></div><p>MSM being divided between front and back-end, one needs to first define a 12 front-end. Then, to create a real state machine, the back-end must be 13 declared: 14 </p><pre class="programlisting">typedef msm::back::state_machine<my_front_end> my_fsm;</pre><p>We now have a fully functional state machine type. The next sections will 15 describe what can be done with it.</p></div><div class="sect2" title="Starting and stopping a state machine"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2312"></a><span class="command"><strong><a name="backend-start"></a></strong></span>Starting and stopping a state 16 machine</h3></div></div></div><p>The <code class="code">start()</code> method starts the state machine, meaning it will 17 activate the initial state, which means in turn that the initial state's 18 entry behavior will be called. We need the start method because you do not 19 always want the entry behavior of the initial state to be called immediately 20 but only when your state machine is ready to process events. A good example 21 of this is when you use a state machine to write an algorithm and each loop 22 back to the initial state is an algorithm call. Each call to start will make 23 the algorithm run once. The <a class="link" href="examples/iPodSearch.cpp" target="_top">iPodSearch</a> example uses this possibility.</p><p>The <code class="code">stop()</code> method works the same way. It will cause the exit 24 actions of the currently active states(s) to be called.</p><p>Both methods are actually not an absolute need. Not calling them will 25 simply cause your first entry or your last exit action not to be 26 called.</p></div><div class="sect2" title="Event dispatching"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2331"></a>Event dispatching</h3></div></div></div><p>The main reason to exist for a state machine is to dispatch events. For 27 MSM, events are objects of a given event type. The object itself can contain 28 data, but the event type is what decides of the transition to be taken. For 29 MSM, if some_event is a given type (a simple struct for example) and e1 and 30 e2 concrete instances of some_event, e1 and e2 are equivalent, from a 31 transition perspective. Of course, e1 and e2 can have different values and 32 you can use them inside actions. Events are dispatched as const reference, 33 so actions cannot modify events for obvious side-effect reasons. To dispatch 34 an event of type some_event, you can simply create one on the fly or 35 instantiate if before processing: </p><pre class="programlisting">my_fsm fsm; fsm.process_event(some_event()); 36some_event e1; fsm.process_event(e1)</pre><p>Creating an event on the fly will be optimized by the compiler so the 37 performance will not degrade.</p></div><div class="sect2" title="Active state(s)"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2340"></a>Active state(s)</h3></div></div></div><p>The backend also offers a way to know which state is active, though you 38 will normally only need this for debugging purposes. If what you need simply 39 is doing something with the active state, <span class="command"><strong><a class="command" href="ch02s02.html#UML-internal-transition">internal transitions</a></strong></span> or 40 <span class="command"><strong><a class="command" href="ch03s05.html#backend-visitor">visitors</a></strong></span> are a better 41 alternative. If you need to know what state is active, const int* 42 current_state() will return an array of state ids. Please refer to the 43 <span class="command"><strong><a class="command" href="ch06s03.html#internals-state-id">internals section</a></strong></span> to 44 know how state ids are generated.</p></div><div class="sect2" title="Serialization"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2354"></a><span class="command"><strong><a name="back-end-serialization"></a></strong></span>Serialization</h3></div></div></div><p>A common need is the ability to save a state machine and restore it at a 45 different time. MSM supports this feature for the basic and functor 46 front-ends, and in a more limited manner for eUML. MSM supports 47 boost::serialization out of the box (by offering a <code class="code">serialize</code> 48 function). Actually, for basic serialization, you need not do much, a MSM 49 state machine is serializable almost like any other type. Without any 50 special work, you can make a state machine remember its state, for 51 example:</p><p> 52 </p><pre class="programlisting">MyFsm fsm; 53// write to archive 54std::ofstream ofs("fsm.txt"); 55// save fsm to archive 56{ 57 boost::archive::text_oarchive oa(ofs); 58 // write class instance to archive 59 oa << fsm; 60} </pre><p> 61 </p><p>Loading back is very similar:</p><p> 62 </p><pre class="programlisting">MyFsm fsm; 63{ 64 // create and open an archive for input 65 std::ifstream ifs("fsm.txt"); 66 boost::archive::text_iarchive ia(ifs); 67 // read class state from archive 68 ia >> fsm; 69} </pre><p> 70 </p><p>This will (de)serialize the state machine itself but not the concrete 71 states' data. This can be done on a per-state basis to reduce the amount of 72 typing necessary. To allow serialization of a concrete state, provide a 73 do_serialize typedef and implement the serialize function:</p><p> 74 </p><pre class="programlisting">struct Empty : public msm::front::state<> 75{ 76 // we want Empty to be serialized. First provide the typedef 77 typedef int do_serialize; 78 // then implement serialize 79 template<class Archive> 80 void serialize(Archive & ar, const unsigned int /* version */) 81 { 82 ar & some_dummy_data; 83 } 84 Empty():some_dummy_data(0){} 85 int some_dummy_data; 86}; </pre><p> 87 </p><p>You can also serialize data contained in the front-end class. Again, you 88 need to provide the typedef and implement serialize:</p><p> 89 </p><pre class="programlisting">struct player_ : public msm::front::state_machine_def<player_> 90{ 91 //we might want to serialize some data contained by the front-end 92 int front_end_data; 93 player_():front_end_data(0){} 94 // to achieve this, provide the typedef 95 typedef int do_serialize; 96 // and implement serialize 97 template<class Archive> 98 void serialize(Archive & ar, const unsigned int ) 99 { 100 ar & front_end_data; 101 } 102... 103}; </pre><p> 104 </p><p>The saving of the back-end data (the current state(s)) is valid for all 105 front-ends, so a front-end written using eUML can be serialized. However, to 106 serialize a concrete state, the macros like 107 <code class="code">BOOST_MSM_EUML_STATE</code> cannot be used, so the state will have 108 to be implemented by directly inheriting from 109 <code class="code">front::euml::euml_state</code>.</p><p>The only limitiation is that the event queues cannot be serialized so 110 serializing must be done in a stable state, when no event is being 111 processed. You can serialize during event processing only if using no queue 112 (deferred or event queue).</p><p>This <a class="link" href="examples/Serialize.cpp" target="_top">example</a> shows a state machine which we serialize after processing an 113 event. The <code class="code">Empty</code> state also has some data to serialize.</p></div><div class="sect2" title="Base state type"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2407"></a><span class="command"><strong><a name="backend-base-state"></a></strong></span>Base state type </h3></div></div></div><p>Sometimes, one needs to customize states to avoid repetition and provide a 114 common functionality, for example in the form of a virtual method. You might 115 also want to make your states polymorphic so that you can call typeid on 116 them for logging or debugging. It is also useful if you need a visitor, like 117 the next section will show. You will notice that all front-ends offer the 118 possibility of adding a base type. Note that all states and state machines 119 must have the same base state, so this could reduce reuse. For example, 120 using the basic front end, you need to:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Add the non-default base state in your msm::front::state<> 121 definition, as first template argument (except for 122 interrupt_states for which it is the second argument, the first 123 one being the event ending the interrupt), for example, 124 my_base_state being your new base state for all states in a 125 given state machine: 126 </p><pre class="programlisting">struct Empty : public msm::front::state<my_base_state></pre><p> 127 Now, my_base_state is your new base state. If it has a virtual 128 function, your states become polymorphic. MSM also provides a 129 default polymorphic base type, 130 <code class="code">msm::front::polymorphic_state</code> 131 </p></li><li class="listitem"><p>Add the user-defined base state in the state machine frontend 132 definition, as a second template argument, for example: 133 </p><pre class="programlisting">struct player_ : public msm::front::state_machine<player_,my_base_state> </pre></li></ul></div><p>You can also ask for a state with a given id (which you might have gotten 134 from current_state()) using <code class="code">const base_state* get_state_by_id(int id) 135 const</code> where base_state is the one you just defined. You can now 136 do something polymorphically.</p></div><div class="sect2" title="Visitor"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2433"></a><span class="command"><strong><a name="backend-visitor"></a></strong></span>Visitor</h3></div></div></div><p>In some cases, having a pointer-to-base of the currently active states is 137 not enough. You might want to call non-virtually a method of the currently 138 active states. It will not be said that MSM forces the virtual keyword down 139 your throat!</p><p>To achieve this goal, MSM provides its own variation of a visitor pattern 140 using the previously described user-defined state technique. If you add to 141 your user-defined base state an <code class="code">accept_sig</code> typedef giving the 142 return value (unused for the moment) and parameters and provide an accept 143 method with this signature, calling visit_current_states will cause accept 144 to be called on the currently active states. Typically, you will also want 145 to provide an empty default accept in your base state in order in order not 146 to force all your states to implement accept. For example your base state 147 could be:</p><pre class="programlisting">struct my_visitable_state 148{ 149 // signature of the accept function 150 typedef args<void> accept_sig; 151 // we also want polymorphic states 152 virtual ~my_visitable_state() {} 153 // default implementation for states who do not need to be visited 154 void accept() const {} 155};</pre><p>This makes your states polymorphic and visitable. In this case, accept is 156 made const and takes no argument. It could also be:</p><pre class="programlisting">struct SomeVisitor {…}; 157struct my_visitable_state 158{ 159 // signature of the accept function 160 typedef args<void,SomeVisitor&> accept_sig; 161 // we also want polymorphic states 162 virtual ~my_visitable_state() {} 163 // default implementation for states who do not need to be visited 164 void accept(SomeVisitor&) const {} 165};</pre><p>And now, <code class="code">accept</code> will take one argument (it could also be 166 non-const). By default, <code class="code">accept</code> takes up to 2 arguments. To get 167 more, set #define BOOST_MSM_VISITOR_ARG_SIZE to another value before 168 including state_machine.hpp. For example:</p><pre class="programlisting">#define BOOST_MSM_VISITOR_ARG_SIZE 3 169#include <boost/msm/back/state_machine.hpp></pre><p>Note that accept will be called on ALL active states <span class="underline">and also automatically on sub-states of a 170 submachine</span>.</p><p><span class="underline">Important warning</span>: The method 171 visit_current_states takes its parameter by value, so if the signature of 172 the accept function is to contain a parameter passed by reference, pass this 173 parameter with a boost:ref/cref to avoid undesired copies or slicing. So, 174 for example, in the above case, call:</p><pre class="programlisting">SomeVisitor vis; sm.visit_current_states(boost::ref(vis));</pre><p>This <a class="link" href="examples/SM-2Arg.cpp" target="_top">example</a> uses a 175 visiting function with 2 arguments.</p></div><div class="sect2" title="Flags"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2476"></a>Flags</h3></div></div></div><p>Flags is a MSM-only concept, supported by all front-ends, which base 176 themselves on the functions: </p><pre class="programlisting">template <class Flag> bool is_flag_active() 177template <class Flag,class BinaryOp> bool is_flag_active()</pre><p>These functions return true if the currently active state(s) support the 178 Flag property. The first variant ORs the result if there are several 179 orthogonal regions, the second one expects OR or AND, for example:</p><pre class="programlisting">my_fsm.is_flag_active<MyFlag>() 180my_fsm.is_flag_active<MyFlag,my_fsm_type::Flag_OR>()</pre><p>Please refer to the front-ends sections for usage examples.</p></div><div class="sect2" title="Getting a state"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2489"></a>Getting a state</h3></div></div></div><p>It is sometimes necessary to have the client code get access to the 181 states' data. After all, the states are created once for good and hang 182 around as long as the state machine does so why not use it? You simply just 183 need sometimes to get information about any state, even inactive ones. An 184 example is if you want to write a coverage tool and know how many times a 185 state was visited. To get a state, use the get_state method giving the state 186 name, for example: </p><pre class="programlisting">player::Stopped* tempstate = p.get_state<player::Stopped*>();</pre><p> or </p><pre class="programlisting">player::Stopped& tempstate2 = p.get_state<player::Stopped&>();</pre><p>depending on your personal taste. </p></div><div class="sect2" title="State machine constructor with arguments"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2502"></a><span class="command"><strong><a name="backend-fsm-constructor-args"></a></strong></span> State machine constructor with arguments </h3></div></div></div><p>You might want to define a state machine with a non-default constructor. 187 For example, you might want to write: </p><pre class="programlisting">struct player_ : public msm::front::state_machine_def<player_> 188{ 189 player_(int some_value){…} 190}; </pre><p>This is possible, using the back-end as forwarding object: </p><pre class="programlisting">typedef msm::back::state_machine<player_ > player; player p(3);</pre><p>The back-end will call the corresponding front-end constructor upon 191 creation.</p><p>You can pass arguments up to the value of the 192 BOOST_MSM_CONSTRUCTOR_ARG_SIZE macro (currently 5) arguments. Change this 193 value before including any header if you need to overwrite the default. </p><p>You can also pass arguments by reference (or const-reference) using 194 boost::ref (or boost::cref):</p><pre class="programlisting">struct player_ : public msm::front::state_machine_def<player_> 195{ 196 player_(SomeType& t, int some_value){…} 197}; 198 199typedef msm::back::state_machine<player_ > player; 200SomeType data; 201player p(boost::ref(data),3); 202 </pre><p>Normally, MSM default-constructs all its states or submachines. There are 203 however cases where you might not want this. An example is when you use a 204 state machine as submachine, and this submachine used the above defined 205 constructors. You can add as first argument of the state machine constructor 206 an expression where existing states are passed and copied:</p><pre class="programlisting">player p( back::states_ << state_1 << ... << state_n , boost::ref(data),3);</pre><p>Where state_1..n are instances of some or all of the states of the state 207 machine. Submachines being state machines, this can recurse, for example, if 208 Playing is a submachine containing a state Song1 having itself a constructor 209 where some data is passed:</p><pre class="programlisting">player p( back::states_ << Playing(back::states_ << Song1(some_Song1_data)) , 210 boost::ref(data),3);</pre><p>It is also possible to replace a given state by a new instance at any time 211 using <code class="code">set_states()</code> and the same syntax, for example: 212 </p><pre class="programlisting">p.set_states( back::states_ << state_1 << ... << state_n );</pre><p>An <a class="link" href="examples/Constructor.cpp" target="_top">example</a> making intensive use of this capability is provided.</p></div><div class="sect2" title="Trading run-time speed for better compile-time / multi-TU compilation"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2542"></a><span class="command"><strong><a name="backend-tradeof-rt-ct"></a></strong></span>Trading run-time speed for 213 better compile-time / multi-TU compilation</h3></div></div></div><p>MSM is optimized for run-time speed at the cost of longer compile-time. 214 This can become a problem with older compilers and big state machines, 215 especially if you don't really care about run-time speed that much and would 216 be satisfied by a performance roughly the same as most state machine 217 libraries. MSM offers a back-end policy to help there. But before you try 218 it, if you are using a VC compiler, deactivate the /Gm compiler option 219 (default for debug builds). This option can cause builds to be 3 times 220 longer... If the compile-time still is a problem, read further. MSM offers a 221 policy which will speed up compiling in two main cases:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>many transition conflicts</p></li><li class="listitem"><p>submachines</p></li></ul></div><p>The back-end <code class="code">msm::back::state_machine</code> has a policy argument 222 (first is the front-end, then the history policy) defaulting to 223 <code class="code">favor_runtime_speed</code>. To switch to 224 <code class="code">favor_compile_time</code>, which is declared in 225 <code class="code"><msm/back/favor_compile_time.hpp></code>, you need to:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>switch the policy to <code class="code">favor_compile_time</code> for the 226 main state machine (and possibly submachines)</p></li><li class="listitem"><p>move the submachine declarations into their own header which 227 includes 228 <code class="code"><msm/back/favor_compile_time.hpp></code></p></li><li class="listitem"><p>add for each submachine a cpp file including your header and 229 calling a macro, which generates helper code, for 230 example:</p><pre class="programlisting">#include "mysubmachine.hpp" 231BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(mysubmachine)</pre></li><li class="listitem"><p>configure your compiler for multi-core compilation</p></li></ul></div><p>You will now compile your state machine on as many cores as you have 232 submachines, which will greatly speed up the compilation if you factor your 233 state machine into smaller submachines.</p><p>Independently, transition conflicts resolution will also be much 234 faster.</p><p>This policy uses boost.any behind the hood, which means that we will lose 235 a feature which MSM offers with the default policy, <a class="link" href="ch03s02.html#event-hierarchy">event hierarchy</a>. The following 236 example takes our iPod example and speeds up compile-time by using this 237 technique. We have:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><a class="link" href="examples/iPod_distributed/iPod.cpp" target="_top">our main 238 state machine and main function</a></p></li><li class="listitem"><p><a class="link" href="examples/iPod_distributed/PlayingMode.hpp" target="_top">PlayingMode moved to a separate header</a></p></li><li class="listitem"><p><a class="link" href="examples/iPod_distributed/PlayingMode.cpp" target="_top">a 239 cpp for PlayingMode</a></p></li><li class="listitem"><p><a class="link" href="examples/iPod_distributed/MenuMode.hpp" target="_top">MenuMode moved to a separate header</a></p></li><li class="listitem"><p><a class="link" href="examples/iPod_distributed/MenuMode.cpp" target="_top">a 240 cpp for MenuMode</a></p></li><li class="listitem"><p><a class="link" href="examples/iPod_distributed/Events.hpp" target="_top">events 241 move to a separate header as all machines use 242 it</a></p></li></ul></div><p> 243 </p></div><div class="sect2" title="Compile-time state machine analysis"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2624"></a><span class="command"><strong><a name="backend-compile-time-analysis"></a></strong></span>Compile-time state machine analysis </h3></div></div></div><p>A MSM state machine being a metaprogram, it is only logical that cheking 244 for the validity of a concrete state machine happens compile-time. To this 245 aim, using the compile-time graph library <a class="link" href="http://www.dynagraph.org/mpl_graph/" target="_top">mpl_graph</a> (delivered at the moment 246 with MSM) from Gordon Woodhull, MSM provides several compile-time checks:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Check that orthogonal regions ar truly orthogonal.</p></li><li class="listitem"><p>Check that all states are either reachable from the initial 247 states or are explicit entries / pseudo-entry states.</p></li></ul></div><p>To make use of this feature, the back-end provides a policy (default is no 248 analysis), <code class="code">msm::back::mpl_graph_fsm_check</code>. For example:</p><pre class="programlisting"> typedef msm::back::state_machine< player_,msm::back::mpl_graph_fsm_check> player; </pre><p>As MSM is now using Boost.Parameter to declare policies, the policy choice 249 can be made at any position after the front-end type (in this case 250 <code class="code">player_</code>).</p><p>In case an error is detected, a compile-time assertion is provoked.</p><p>This feature is not enabled by default because it has a non-neglectable 251 compile-time cost. The algorithm is linear if no explicit or pseudo entry 252 states are found in the state machine, unfortunately still O(number of 253 states * number of entry states) otherwise. This will be improved in future 254 versions of MSM.</p><p>The same algorithm is also used in case you want to omit providing the 255 region index in the <span class="command"><strong><a class="command" href="ch03s02.html#explicit-entry-no-region-id">explicit entry / pseudo entry state</a></strong></span> declaration.</p><p>The author's advice is to enable the checks after any state machine 256 structure change and disable it again after sucessful analysis.</p><p>The <a class="link" href="examples/TestErrorOrthogonality.cpp" target="_top">following example</a> provokes an assertion if one of the first two lines 257 of the transition table is used.</p></div><div class="sect2" title="Enqueueing events for later processing"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2668"></a><span class="command"><strong><a name="backend-enqueueing"></a></strong></span> Enqueueing events for later 258 processing </h3></div></div></div><p>Calling <code class="code">process_event(Event const&)</code> will immediately 259 process the event with run-to-completion semantics. You can also enqueue the 260 events and delay their processing by calling <code class="code">enqueue_event(Event 261 const&)</code> instead. Calling <code class="code">execute_queued_events()</code> 262 will then process all enqueued events (in FIFO order). Calling 263 <code class="code">execute_single_queued_event()</code> will execute the oldest 264 enqueued event.</p><p>You can query the queue size by calling <code class="code">get_message_queue_size()</code>.</p></div><div class="sect2" title="Customizing the message queues"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2691"></a><span class="command"><strong><a name="backend-queues"></a></strong></span> Customizing the message queues </h3></div></div></div><p>MSM uses by default a std::deque for its queues (one message queue for 265 events generated during run-to-completion or with 266 <code class="code">enqueue_event</code>, one for deferred events). Unfortunately, on some 267 STL implementations, it is a very expensive container in size and copying 268 time. Should this be a problem, MSM offers an alternative based on 269 boost::circular_buffer. The policy is msm::back::queue_container_circular. 270 To use it, you need to provide it to the back-end definition:</p><pre class="programlisting"> typedef msm::back::state_machine< player_,msm::back::queue_container_circular> player; </pre><p>You can access the queues with get_message_queue and get_deferred_queue, 271 both returning a reference or a const reference to the queues themselves. 272 Boost::circular_buffer is outside of the scope of this documentation. What 273 you will however need to define is the queue capacity (initially is 0) to 274 what you think your queue will at most grow, for example (size 1 is 275 common):</p><pre class="programlisting"> fsm.get_message_queue().set_capacity(1); </pre></div><div class="sect2" title="Policy definition with Boost.Parameter"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2706"></a><span class="command"><strong><a name="backend-boost-parameter"></a></strong></span>Policy definition with Boost.Parameter </h3></div></div></div><p>MSM uses Boost.Parameter to allow easier definition of 276 back::state_machine<> policy arguments (all except the front-end). This 277 allows you to define policy arguments (history, compile-time / run-time, 278 state machine analysis, container for the queues) at any position, in any 279 number. For example: </p><pre class="programlisting"> typedef msm::back::state_machine< player_,msm::back::mpl_graph_fsm_check> player; 280 typedef msm::back::state_machine< player_,msm::back::AlwaysHistory> player; 281 typedef msm::back::state_machine< player_,msm::back::mpl_graph_fsm_check,msm::back::AlwaysHistory> player; 282 typedef msm::back::state_machine< player_,msm::back::AlwaysHistory,msm::back::mpl_graph_fsm_check> player; </pre></div><div class="sect2" title="Choosing when to switch active states"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2714"></a><span class="command"><strong><a name="backend-state-switch"></a></strong></span>Choosing when to switch active 283 states </h3></div></div></div><p>The UML Standard is silent about a very important question: when a 284 transition fires, at which exact point is the target state the new active 285 state of a state machine? At the end of the transition? After the source 286 state has been left? What if an exception is thrown? The Standard considers 287 that run-to-completion means a transition completes in almost no time. But 288 even this can be in some conditions a very very long time. Consider the 289 following example. We have a state machine representing a network 290 connection. We can be <code class="code">Connected</code> and <code class="code">Disconnected</code>. When we move from one 291 state to another, we send a (Boost) Signal to another entity. By default, 292 MSM makes the target state as the new state after the transition is 293 completed. We want to send a signal based on a flag is_connected which is 294 true when in state Connected.</p><p>We are in state <code class="code">Disconnected</code> and receive an event <code class="code">connect</code>. The transition 295 action will ask the state machine <code class="code">is_flag_active<is_connected></code> and will 296 get... false because we are still in <code class="code">Disconnected</code>. Hmm, what to do? We could 297 queue the action and execute it later, but it means an extra queue, more 298 work and higher run-time.</p><p>MSM provides the possibility (in form of a policy) for a front-end to 299 decide when the target state becomes active. It can be:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>before the transition fires, if the guard will allow the 300 transition to fire: 301 <code class="code">active_state_switch_before_transition</code></p></li><li class="listitem"><p>after calling the exit action of the source state: 302 <code class="code">active_state_switch_after_exit</code></p></li><li class="listitem"><p>after the transition action is executed: 303 <code class="code">active_state_switch_after_transition_action</code></p></li><li class="listitem"><p>after the entry action of the target state is executed 304 (default): <code class="code">active_state_switch_after_entry</code></p></li></ul></div><p>The problem and the solution is shown for the 305 <a class="link" href="examples/ActiveStateSetBeforeTransition.cpp" target="_top">functor-front-end</a> 306 and <a class="link" href="examples/ActivateStateBeforeTransitionEuml.cpp" target="_top">eUML</a>. Removing <code class="code">active_state_switch_before_transition</code> 307 will show the default state. </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch03s04.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch03.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch04.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">eUML </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 4. Performance / Compilers</td></tr></table></div></body></html>