ch03s05.html 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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&nbsp;3.&nbsp;Tutorial"><link rel="prev" href="ch03s04.html" title="eUML"><link rel="next" href="ch04.html" title="Chapter&nbsp;4.&nbsp; 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>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;3.&nbsp;Tutorial</th><td width="20%" align="right">&nbsp;<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&lt;my_front_end&gt; 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());
  36. some_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
  54. std::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 &lt;&lt; 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 &gt;&gt; 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&lt;&gt;
  75. {
  76. // we want Empty to be serialized. First provide the typedef
  77. typedef int do_serialize;
  78. // then implement serialize
  79. template&lt;class Archive&gt;
  80. void serialize(Archive &amp; ar, const unsigned int /* version */)
  81. {
  82. ar &amp; 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&lt;player_&gt;
  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&lt;class Archive&gt;
  98. void serialize(Archive &amp; ar, const unsigned int )
  99. {
  100. ar &amp; 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&lt;&gt;
  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&lt;my_base_state&gt;</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&lt;player_,my_base_state&gt; </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&lt;void&gt; 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 {&#8230;};
  157. struct my_visitable_state
  158. {
  159. // signature of the accept function
  160. typedef args&lt;void,SomeVisitor&amp;&gt; 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&amp;) 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 &lt;boost/msm/back/state_machine.hpp&gt;</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 &lt;class Flag&gt; bool is_flag_active()
  177. template &lt;class Flag,class BinaryOp&gt; 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&lt;MyFlag&gt;()
  180. my_fsm.is_flag_active&lt;MyFlag,my_fsm_type::Flag_OR&gt;()</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&lt;player::Stopped*&gt;();</pre><p> or </p><pre class="programlisting">player::Stopped&amp; tempstate2 = p.get_state&lt;player::Stopped&amp;&gt;();</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&lt;player_&gt;
  188. {
  189. player_(int some_value){&#8230;}
  190. }; </pre><p>This is possible, using the back-end as forwarding object: </p><pre class="programlisting">typedef msm::back::state_machine&lt;player_ &gt; 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&lt;player_&gt;
  195. {
  196. player_(SomeType&amp; t, int some_value){&#8230;}
  197. };
  198. typedef msm::back::state_machine&lt;player_ &gt; player;
  199. SomeType data;
  200. player p(boost::ref(data),3);
  201. </pre><p>Normally, MSM default-constructs all its states or submachines. There are
  202. however cases where you might not want this. An example is when you use a
  203. state machine as submachine, and this submachine used the above defined
  204. constructors. You can add as first argument of the state machine constructor
  205. an expression where existing states are passed and copied:</p><pre class="programlisting">player p( back::states_ &lt;&lt; state_1 &lt;&lt; ... &lt;&lt; state_n , boost::ref(data),3);</pre><p>Where state_1..n are instances of some or all of the states of the state
  206. machine. Submachines being state machines, this can recurse, for example, if
  207. Playing is a submachine containing a state Song1 having itself a constructor
  208. where some data is passed:</p><pre class="programlisting">player p( back::states_ &lt;&lt; Playing(back::states_ &lt;&lt; Song1(some_Song1_data)) ,
  209. boost::ref(data),3);</pre><p>It is also possible to replace a given state by a new instance at any time
  210. using <code class="code">set_states()</code> and the same syntax, for example:
  211. </p><pre class="programlisting">p.set_states( back::states_ &lt;&lt; state_1 &lt;&lt; ... &lt;&lt; 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
  212. 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.
  213. This can become a problem with older compilers and big state machines,
  214. especially if you don't really care about run-time speed that much and would
  215. be satisfied by a performance roughly the same as most state machine
  216. libraries. MSM offers a back-end policy to help there. But before you try
  217. it, if you are using a VC compiler, deactivate the /Gm compiler option
  218. (default for debug builds). This option can cause builds to be 3 times
  219. longer... If the compile-time still is a problem, read further. MSM offers a
  220. 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
  221. (first is the front-end, then the history policy) defaulting to
  222. <code class="code">favor_runtime_speed</code>. To switch to
  223. <code class="code">favor_compile_time</code>, which is declared in
  224. <code class="code">&lt;msm/back/favor_compile_time.hpp&gt;</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
  225. main state machine (and possibly submachines)</p></li><li class="listitem"><p>move the submachine declarations into their own header which
  226. includes
  227. <code class="code">&lt;msm/back/favor_compile_time.hpp&gt;</code></p></li><li class="listitem"><p>add for each submachine a cpp file including your header and
  228. calling a macro, which generates helper code, for
  229. example:</p><pre class="programlisting">#include "mysubmachine.hpp"
  230. BOOST_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
  231. submachines, which will greatly speed up the compilation if you factor your
  232. state machine into smaller submachines.</p><p>Independently, transition conflicts resolution will also be much
  233. faster.</p><p>This policy uses boost.any behind the hood, which means that we will lose
  234. a feature which MSM offers with the default policy, <a class="link" href="ch03s02.html#event-hierarchy">event hierarchy</a>. The following
  235. example takes our iPod example and speeds up compile-time by using this
  236. 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
  237. 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
  238. 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
  239. cpp for MenuMode</a></p></li><li class="listitem"><p><a class="link" href="examples/iPod_distributed/Events.hpp" target="_top">events
  240. move to a separate header as all machines use
  241. it</a></p></li></ul></div><p>
  242. </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
  243. for the validity of a concrete state machine happens compile-time. To this
  244. 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
  245. 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
  246. 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
  247. analysis), <code class="code">msm::back::mpl_graph_fsm_check</code>. For example:</p><pre class="programlisting"> typedef msm::back::state_machine&lt; player_,msm::back::mpl_graph_fsm_check&gt; player; </pre><p>As MSM is now using Boost.Parameter to declare policies, the policy choice
  248. can be made at any position after the front-end type (in this case
  249. <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
  250. compile-time cost. The algorithm is linear if no explicit or pseudo entry
  251. states are found in the state machine, unfortunately still O(number of
  252. states * number of entry states) otherwise. This will be improved in future
  253. versions of MSM.</p><p>The same algorithm is also used in case you want to omit providing the
  254. 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
  255. 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
  256. 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
  257. processing </h3></div></div></div><p>Calling <code class="code">process_event(Event const&amp;)</code> will immediately
  258. process the event with run-to-completion semantics. You can also enqueue the
  259. events and delay their processing by calling <code class="code">enqueue_event(Event
  260. const&amp;)</code> instead. Calling <code class="code">execute_queued_events()</code>
  261. will then process all enqueued events (in FIFO order). Calling
  262. <code class="code">execute_single_queued_event()</code> will execute the oldest
  263. 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
  264. events generated during run-to-completion or with
  265. <code class="code">enqueue_event</code>, one for deferred events). Unfortunately, on some
  266. STL implementations, it is a very expensive container in size and copying
  267. time. Should this be a problem, MSM offers an alternative based on
  268. boost::circular_buffer. The policy is msm::back::queue_container_circular.
  269. To use it, you need to provide it to the back-end definition:</p><pre class="programlisting"> typedef msm::back::state_machine&lt; player_,msm::back::queue_container_circular&gt; player; </pre><p>You can access the queues with get_message_queue and get_deferred_queue,
  270. both returning a reference or a const reference to the queues themselves.
  271. Boost::circular_buffer is outside of the scope of this documentation. What
  272. you will however need to define is the queue capacity (initially is 0) to
  273. what you think your queue will at most grow, for example (size 1 is
  274. 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
  275. back::state_machine&lt;&gt; policy arguments (all except the front-end). This
  276. allows you to define policy arguments (history, compile-time / run-time,
  277. state machine analysis, container for the queues) at any position, in any
  278. number. For example: </p><pre class="programlisting"> typedef msm::back::state_machine&lt; player_,msm::back::mpl_graph_fsm_check&gt; player;
  279. typedef msm::back::state_machine&lt; player_,msm::back::AlwaysHistory&gt; player;
  280. typedef msm::back::state_machine&lt; player_,msm::back::mpl_graph_fsm_check,msm::back::AlwaysHistory&gt; player;
  281. typedef msm::back::state_machine&lt; player_,msm::back::AlwaysHistory,msm::back::mpl_graph_fsm_check&gt; 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
  282. states </h3></div></div></div><p>The UML Standard is silent about a very important question: when a
  283. transition fires, at which exact point is the target state the new active
  284. state of a state machine? At the end of the transition? After the source
  285. state has been left? What if an exception is thrown? The Standard considers
  286. that run-to-completion means a transition completes in almost no time. But
  287. even this can be in some conditions a very very long time. Consider the
  288. following example. We have a state machine representing a network
  289. connection. We can be <code class="code">Connected</code> and <code class="code">Disconnected</code>. When we move from one
  290. state to another, we send a (Boost) Signal to another entity. By default,
  291. MSM makes the target state as the new state after the transition is
  292. completed. We want to send a signal based on a flag is_connected which is
  293. 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
  294. action will ask the state machine <code class="code">is_flag_active&lt;is_connected&gt;</code> and will
  295. get... false because we are still in <code class="code">Disconnected</code>. Hmm, what to do? We could
  296. queue the action and execute it later, but it means an extra queue, more
  297. work and higher run-time.</p><p>MSM provides the possibility (in form of a policy) for a front-end to
  298. 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
  299. transition to fire:
  300. <code class="code">active_state_switch_before_transition</code></p></li><li class="listitem"><p>after calling the exit action of the source state:
  301. <code class="code">active_state_switch_after_exit</code></p></li><li class="listitem"><p>after the transition action is executed:
  302. <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
  303. (default): <code class="code">active_state_switch_after_entry</code></p></li></ul></div><p>The problem and the solution is shown for the
  304. <a class="link" href="examples/ActiveStateSetBeforeTransition.cpp" target="_top">functor-front-end</a>
  305. and <a class="link" href="examples/ActivateStateBeforeTransitionEuml.cpp" target="_top">eUML</a>. Removing <code class="code">active_state_switch_before_transition</code>
  306. 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>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch03.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch04.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">eUML&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;Chapter&nbsp;4.&nbsp; Performance / Compilers</td></tr></table></div></body></html>