Boost logo

Boost Users :

Subject: Re: [Boost-users] [MSM] state transitions and exceptions
From: Christophe Henry (christophe.j.henry_at_[hidden])
Date: 2012-03-29 15:46:27


> Everyone,
>
> I did just get around to give the MSM a first shot and I have say I am
> impressed at the neat design, the ease of use, "understandability",
> tutorial ... exceptional work. Really great and it helped me a great
> deal so far. So thanks a bunch for this teriffic addition to boost.
> That's the kind of stuff I love boost for.

Thanks :) Happy you like it.

> There is one question however that puzzles me. How can / do I prevent
> state transistions when a transition function throws?
>
> Most transition functions are defined like that:
>
> void so_transition(event::Cause const &e) {
>
> methodCausingAnException();
> }
>
> The tutorial only mentions this at the very end of the back-end docs
> and this is not clear to me. I have stuff inside my transitions that
> may throw and the example text mentiones other valid examples (like
> connect() logic). So what am I supposed to do here?
>
> This?
>
> void so_transition(event::Cause const &e) {
> try {
> methodCausingAnException();
> } catch (const std::exception &sex) {
> return ???
> }
> }
>
> The type is void and I can't return anything that would prevent the
> transition.
> Or should I just let the exception pass? What is the correct way?
>
> Suggestions are appreciated,

First of all, I have to give a word of caution. The UML Standard does not
foresee exceptions and they don't mix well with the run-to-completion
algorithm on which state machines rely. Try to avoid them if you can.

This being said, exceptions happen in C++ ;-)
By default, MSM catches them, then calls the exception_caught handler, which
by default is:

    template <class FSM,class Event>
    void exception_caught (Event const&,FSM&,std::exception& )
    {
        BOOST_ASSERT(false);
    }

Like the no_transition handler, you can overwrite it with your own.
When this is called, the transition is interrupted where it was and ceases
processing. This leaves you in a not very desirable state because you have
been interrupted somewhere in the guard/exit/action/entry chain.
When this happens, I advise you to process to yourself an error event to
handle this gracefully. For example:

    template <class FSM,class Event>
    void exception_caught (Event const&,FSM& fsm,std::exception& )
    {
        fsm.process_event(ErrorConnection());
    }
But you still are somewhere in the middle of your transition. I think an
elegant option would be to catch the exception in your action, then process
yourself an error event. For example, using the more powerful functor
front-end (providing you the fsm as parameter):

struct so_transition
{
     template <class EVT,class FSM,class SourceState,class TargetState>
     void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
     {
          try {
             methodCausingAnException();
         }
         catch (const std::exception &) {
             fsm.process_event(ErrorConnection());
         }
     }
};

You can prevent MSM from catching the exception by activating in your front
end a switch:

typedef int no_exception_thrown;

Then, you get the exception thrown from your process_event call.

In any case, the transition where the exception occurs is terminated and you
don't need to terminate yourself.

> Stephan

HTH,
Christophe


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net