Sophie

Sophie

distrib > Fedora > 14 > i386 > by-pkgid > 623999701586b0ea103ff2ccad7954a6 > files > 7844

boost-doc-1.44.0-1.fc14.noarch.rpm

<html><head>
      <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
   <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) V2.10"><link rel="up" href="ch03.html" title="Chapter&nbsp;3.&nbsp;Tutorial"><link rel="prev" href="ch03s04.html" title="eUML (experimental)"><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="d0e3479"></a>Back-end</h2></div></div></div><p>There is, at the moment, one back-end. This back-end contains the library
                    engine and defines the performance and functionality trade-offs. The currently
                    available back-end implements most of the functionality defined by the UML 2.0
                    standard at very high runtime speed, in exchange for longer compile-time. The
                    runtime speed is due to a constant-time double-dispatch and self-adapting
                    capabilities allowing the framework to adapt itself to the features used by a
                    given concrete state machine. All unneeded features either disable themselves or
                    can be manually disabled. See section 5.1 for a complete description of the
                    run-to-completion algorithm.</p><div class="sect2" title="Creation"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3484"></a>Creation </h3></div></div></div><p>MSM being divided between front and back-end, one needs to first define a
                        front-end. Then, to create a real state machine, the back-end must be
                        declared:
                        </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
                        describe what can be done with it.</p></div><div class="sect2" title="Starting a state machine"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3493"></a><span class="command"><strong><a name="backend-start"></a></strong></span>Starting a state machine</h3></div></div></div><p>The <code class="code">start</code> method starts the state machine, meaning it will
                        activate the initial state, which means in turn that the initial state's
                        entry behavior will be called. We need the start method because you do not
                        always want the entry behavior of the initial state to be called immediately
                        but only when your state machine is ready to process events. A good example
                        of this is when you use a state machine to write an algorithm and each loop
                        back to the initial state is an algorithm call. Each call to start will make
                        the algorithm run once. The <a class="link" href="examples/iPodSearch.cpp" target="_top">iPodSearch</a> example uses this possibility.</p></div><div class="sect2" title="Event dispatching"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3505"></a>Event dispatching</h3></div></div></div><p>The main reason to exist for a state machine is to dispatch events. For
                        MSM, events are objects of a given event type. The object itself can contain
                        data, but the event type is what decides of the transition to be taken. For
                        MSM, if some_event is a given type (a simple struct for example) and e1 and
                        e2 concrete instances of some_event, e1 and e2 are equivalent, from a
                        transition perspective. Of course, e1 and e2 can have different values and
                        you can use them inside actions. Events are dispatched as const reference,
                        so actions cannot modify events for obvious side-effect reasons. To dispatch
                        an event of type some_event, you can simply create one on the fly or
                        instantiate if before processing: </p><pre class="programlisting">my_fsm fsm; fsm.process_event(some_event());
some_event e1; fsm.process_event(e1)</pre><p>Creating an event on the fly will be optimized by the compiler so the
                        performance will not degrade.</p></div><div class="sect2" title="Active state(s)"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3514"></a>Active state(s)</h3></div></div></div><p>The backend also offers a way to know which state is active, though you
                        will normally only need this for debugging purposes. If what you need simply
                        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
                            <span class="command"><strong><a class="command" href="ch03s05.html#backend-visitor">visitors</a></strong></span> are a better
                        alternative. If you need to know what state is active, const int*
                        current_state() will return an array of state ids. Please refer to the
                            <span class="command"><strong><a class="command" href="ch06s03.html#internals-state-id">internals section</a></strong></span> to
                        know how state ids are generated.</p></div><div class="sect2" title="Base state type"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3528"></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
                        common functionality, for example in the form of a virtual method. You might
                        also want to make your states polymorphic so that you can call typeid on
                        them for logging or debugging. It is also useful if you need a visitor, like
                        the next section will show. You will notice that all front-ends offer the
                        possibility of adding a base type. Note that all states and state machines
                        must have the same base state, so this could reduce reuse. For example,
                        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;
                                    definition, as first template argument (except for
                                    interrupt_states for which it is the second argument, the first
                                    one being the event ending the interrupt), for example,
                                    my_base_state being your new base state for all states in a
                                    given state machine:
                                    </p><pre class="programlisting">struct Empty : public msm::front::state&lt;my_base_state&gt;</pre><p>
                                    Now, my_base_state is your new base state. If it has a virtual
                                    function, your states become polymorphic. MSM also provides a
                                    default polymorphic base type,
                                        <code class="code">msm::front::polymorphic_state</code>
                                </p></li><li class="listitem"><p>Add the user-defined base state in the state machine frontend
                                    definition, as a second template argument, for example:
                                    </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
                        from current_state()) using <code class="code">const base_state* get_state_by_id(int id)
                            const</code> where base_state is the one you just defined. You can now
                        do something polymorphically.</p></div><div class="sect2" title="Visitor"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3554"></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
                        not enough. You might want to call non-virtually a method of the currently
                        active states. It will not be said that MSM forces the virtual keyword down
                        your throat!</p><p>To achieve this goal, MSM provides its own variation of a visitor pattern
                        using the previously described user-defined state technique. If you add to
                        your user-defined base state an <code class="code">accept_sig</code> typedef giving the
                        return value (unused for the moment) and parameters and provide an accept
                        method with this signature, calling visit_current_states will cause accept
                        to be called on the currently active states. Typically, you will also want
                        to provide an empty default accept in your base state in order in order not
                        to force all your states to implement accept. For example your base state
                        could be:</p><pre class="programlisting">struct my_visitable_state
{
   // signature of the accept function
   typedef args&lt;void&gt; accept_sig;
   // we also want polymorphic states
   virtual ~my_visitable_state() {}
   // default implementation for states who do not need to be visited
   void accept() const {}
};</pre><p>This makes your states polymorphic and visitable. In this case, accept is
                        made const and takes no argument. It could also be:</p><pre class="programlisting">struct SomeVisitor {&#8230;};
struct my_visitable_state
{
    // signature of the accept function
    typedef args&lt;void,SomeVisitor&amp;&gt; accept_sig;
    // we also want polymorphic states
    virtual ~my_visitable_state() {}
    // default implementation for states who do not need to be visited
    void accept(SomeVisitor&amp;) const {}
};</pre><p>And now, <code class="code">accept</code> will take one argument (it could also be
                        non-const). By default, <code class="code">accept</code> takes up to 2 arguments. To get
                        more, set #define BOOST_MSM_VISITOR_ARG_SIZE to another value before
                        including state_machine.hpp. For example:</p><pre class="programlisting">#define BOOST_MSM_VISITOR_ARG_SIZE 3
#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
                            submachine</span>.</p><p><span class="underline">Important warning</span>: The method
                        visit_current_states takes its parameter by value, so if the signature of
                        the accept function is to contain a parameter passed by reference, pass this
                        parameter with a boost:ref/cref to avoid undesired copies or slicing. So,
                        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
                        visiting function with 2 arguments.</p></div><div class="sect2" title="Flags"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3597"></a>Flags</h3></div></div></div><p>Flags is a MSM-only concept, supported by all front-ends, which base
                        themselves on the functions: </p><pre class="programlisting">template &lt;class Flag&gt; bool is_flag_active()
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
                        Flag property. The first variant ORs the result if there are several
                        orthogonal regions, the second one expects OR or AND, for example:</p><pre class="programlisting">my_fsm.is_flag_active&lt;MyFlag&gt;()
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="d0e3610"></a>Getting a state</h3></div></div></div><p>It is sometimes necessary to have the client code get access to the
                        states' data. After all, the states are created once for good and hang
                        around as long as the state machine does so why not use it? You simply just
                        need sometimes to get information about any state, even inactive ones. An
                        example is if you want to write a coverage tool and know how many times a
                        state was visited. To get a state, use the get_state method giving the state
                        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="d0e3623"></a> State machine constructor with arguments </h3></div></div></div><p>You might want to define a state machine with a non-default constructor.
                        For example, you might want to write: </p><pre class="programlisting">struct player_ : public msm::front::state_machine_def&lt;player_&gt; 
{ 
    player_(int some_value){&#8230;} 
}; </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
                        creation.</p><p>You can pass arguments up to the value of the
                        BOOST_MSM_CONSTRUCTOR_ARG_SIZE macro (currently 5) arguments. Change this
                        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
                        boost::ref (or boost::cref):</p><pre class="programlisting">struct player_ : public msm::front::state_machine_def&lt;player_&gt;  
{
   player_(SomeType&amp; t, int some_value){&#8230;}  
}; 

typedef msm::back::state_machine&lt;player_ &gt; player; 
SomeType data;
player p(boost::ref(data),3);
                        </pre></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="d0e3642"></a><span class="command"><strong><a name="backend-tradeof-rt-ct"></a></strong></span>Trading run-time speed for
                        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.
                        This can become a problem with older compilers and big state machines,
                        especially if you don't really care about run-time speed that much and would
                        be satisfied by a performance roughly the same as most state machine
                        libraries. MSM offers a back-end policy to help there. But before you try
                        it, if you are using a VC compiler, deactivate the /Gm compiler option
                        (default for debug builds). This option can cause builds to be 3 times
                        longer... If the compile-time still is a problem, read further. MSM offers a
                        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 third template
                        argument (first is the front-end, second is the history policy) defaulting
                        to <code class="code">favor_runtime_speed</code>. To switch to
                            <code class="code">favor_compile_time</code>, which is declared in
                            <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
                                    main state machine (and possibly submachines)</p></li><li class="listitem"><p>move the submachine declarations into their own header which
                                    includes
                                    <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
                                    calling a macro, which generates helper code, for
                                    example:</p><pre class="programlisting">#include "mysubmachine.hpp"
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
                        submachines, which will greatly speed up the compilation if you factor your
                        state machine into smaller submachines.</p><p>Independently, transition conflicts resolution will also be much
                        faster.</p><p>This policy uses boost.any behind the hood, which means that we will lose
                        one feature which MSM offers with the default policy, <a class="link" href="ch03s02.html#event-hierarchy">event hierarchy</a>. The following
                        example takes our iPod example and speeds up compile-time by using this
                        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
                                        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
                                        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
                                        cpp for MenuMode</a></p></li><li class="listitem"><p><a class="link" href="examples/iPod_distributed/Events.hpp" target="_top">events
                                        move to a separate header as all machines use
                                    it</a></p></li></ul></div><p>
                    </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 (experimental)&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>