2009-06-26 7 views
1

Des idées pour résoudre ce problème?Aide pour Boost.Statechart bug

utilisant 1.39_0 sur ubuntu 8,10 w/g ++ 4.3.2

Dans le diagramme d'états qui suit, l'expression "BUGGY" est imprimé trois fois . On s'attendrait à ce que l'événement déclenche seulement un "BUGGY". Dans le cas du projet sur lequel je travaille, je ne peux pas retourner discard_event() car j'ai besoin que l'événement atteigne plusieurs états (généralement en profondeur dans un ensemble d'états orthogonaux). S'il y a une solution de contournement que peut être appliquée au lieu de modifier le graphique, j'aimerais savoir.

$ cat bug.cpp

#include <boost/intrusive_ptr.hpp> 
#include <boost/mpl/list.hpp> #include <boost/statechart/custom_reaction.hpp> 
#include <boost/statechart/event.hpp> 
#include <boost/statechart/simple_state.hpp> 
#include <boost/statechart/state.hpp> 
#include <boost/statechart/state_machine.hpp> 
#include <iostream> 

using namespace std; 
namespace sc = boost::statechart; 
namespace mpl = boost::mpl; 

struct evSay : sc::event<evSay>{ }; 
struct top; 
struct c1; 
struct c2; 
struct c3; 
struct sm : public sc::state_machine<sm,top> { }; 

struct top : sc::simple_state<top,sm,mpl::list<c1,c2,c3> > { 
     typedef sc::custom_reaction<evSay> reactions; 
     sc::result react(const evSay &) { 
       cout<<"BUGGY"<<endl; 
       return forward_event(); 
     } 
}; 

struct c1 : sc::simple_state <c1, top::orthogonal<0> > { }; 

struct c2 : sc::simple_state <c2, top::orthogonal<1> > { }; 

struct c3 : sc::state <c3, top::orthogonal<2> > { 
     c3(my_context ctx) : my_base(ctx) { 
       post_event(boost::intrusive_ptr<evSay> (
           new evSay())); 
     } 
}; 

int main() { 
     sm* fsm = new sm(); 
     fsm->initiate(); 
     delete fsm; 
     return 0; 
} 

$ g ++ bug.cpp & & ./a.out
BUGGY
BUGGY
BUGGY

EDIT ::

C'est un exemple Statemachine qui montre mon problème que je rencontre dans mon beaucoup plus grand que je travaille réellement ng sur. Je sais que le top enverra evSay. Notez que c1, c2, c3 ne réagissent pas à evSay. Voici un exemple où j'ai besoin d'un transfert pour que deux états puissent réagir à evSay.

#include <boost/intrusive_ptr.hpp>  
#include <boost/mpl/list.hpp>  
#include <boost/statechart/custom_reaction.hpp> 
#include <boost/statechart/event.hpp> 
#include <boost/statechart/simple_state.hpp> 
#include <boost/statechart/state.hpp> 
#include <boost/statechart/state_machine.hpp>  
#include <iostream> 
using namespace std; 
namespace sc = boost::statechart; 
namespace mpl = boost::mpl; 
namespace BUG { 
struct evSay : sc::event<evSay>{ }; 
struct top;struct c1;struct c2;struct c3;struct c2_1; 

struct sm : public sc::state_machine<sm,top> { }; 

struct top : sc::simple_state<top,sm,mpl::list<c1,c2,c3> > { 
    typedef sc::simple_state<top,sm,mpl::list<c1,c2,c3> > my_type; 
    typedef sc::custom_reaction<evSay> reactions; 
    sc::result react(const evSay &) { 
     cout<<"BUGGY"<<endl; 
     return forward_event(); 
    } 
}; 

struct c1 : sc::simple_state <c1, top::orthogonal<0> > { }; 
struct c2 : sc::simple_state <c2, top::orthogonal<1>, c2_1 > { }; 
struct c3 : sc::state <c3, top::orthogonal<2> > { 
    c3(my_context ctx) : my_base(ctx) { 
     post_event(boost::intrusive_ptr<evSay> (
       new evSay())); 
    } 
}; 

struct c2_1 : sc::simple_state<c2_1, c2 > { 
    typedef sc::custom_reaction<evSay> reactions; 
    sc::result react(const evSay &) { 
     cout<<"CHILD REACTION"<<endl; 
     return forward_event(); 
    } 
}; 
} 

int main() 
{ 
    BUG::sm* fsm = new BUG::sm(); 
    fsm->initiate(); 
    delete fsm; 
    return 0; 
} 

sortie: BUGGY
ENFANT RÉACTION
BUGGY
BUGGY

Répondre

1

Déplacer la réaction que vous voulez jusqu'à un état enfant de l'état top. Cela le sort de la ligne des événements forward_state. Je ne l'ai pas implémenté comme un type interne, mais vous pourriez le faire.

#include <boost/intrusive_ptr.hpp>  
#include <boost/mpl/list.hpp>  
#include <boost/statechart/custom_reaction.hpp> 
#include <boost/statechart/event.hpp> 
#include <boost/statechart/simple_state.hpp> 
#include <boost/statechart/state.hpp> 
#include <boost/statechart/state_machine.hpp>  
#include <iostream> 
using namespace std; 
namespace sc = boost::statechart; 
namespace mpl = boost::mpl; 


struct evSay : sc::event<evSay>{ }; 

struct top;struct c1;struct c2;struct c3;struct c2_1;struct sub_1; 

struct sm : public sc::state_machine<sm,top> { }; 

struct top : sc::simple_state<top,sm, mpl::list<c1,c2,c3, sub_1> > { }; 

struct sub_1 : sc::simple_state<sub_1, top::orthogonal<3> > { 
    typedef sc::custom_reaction<evSay> reactions; 
    sc::result react(const evSay &) { 
     cout<<"PARENT REACTION"<<endl; 
     return forward_event(); 
    } 
}; 

struct c1 : sc::simple_state <c1, top::orthogonal<0> > { }; 
struct c2 : sc::simple_state <c2, top::orthogonal<1>, c2_1 > { }; 
struct c3 : sc::simple_state <c3, top::orthogonal<2> > { }; 

struct c2_1 : sc::simple_state<c2_1, c2 > { 
    typedef sc::custom_reaction<evSay> reactions; 
    sc::result react(const evSay &) { 
     cout<<"CHILD REACTION"<<endl; 
     return forward_event(); 
    } 
}; 

int main() 
{ 
    sm* fsm = new sm(); 
    fsm->initiate(); 
    fsm->process_event( evSay() ); 
    delete fsm; 
    return 0; 
} 

~$g++ test.cpp -I Downloads/boost_1_45_0
~$./a.out
ENFANT RÉACTION
PARENT RÉACTION

0

on peut attendre de l'événement ne ferait que un déclencheur "BUGGY".

Je ne serais pas honnête. Vous spécifiez trois états orthogonaux, avec un react() défini sur un état externe. Si je comprends bien (*) vous avez trois états les plus intimes, tant que vous continuez à avancer l'événement, tous les trois seront traités. Chacun de ces trois n'a pas de réaction, donc il va chercher une réaction dans un état extérieur, et trouve un dans top et l'appelle, alors comme le résultat est un forward sélectionne arbitrairement le prochain pas encore visité état le plus intime, pour lequel la même chose s'applique.

Je ne peux pas retourner discard_event() comme je l'ai besoin de l'événement pour atteindre plusieurs états (généralement profonds dans un ensemble d'états orthogonaux).

Mais c'est exactement ce que vous réalisez ici. Vous dites que vous voulez atteindre plusieurs états, mais vous ne voulez pas que la réaction() de ces états se déclenche? Cela n'a pas beaucoup de sens d'être honnête.

Il est difficile de donner des conseils car vous n'essayez manifestement pas d'imprimer une 'bogue' une seule fois, qu'essayez-vous exactement d'accomplir?

(*) pour l'enregistrement, je n'ai joué avec state_machine un peu quand il était neuf, jamais utilisé dans le code de production, donc je ne suis pas du tout un expert

+0

Je veux TOP réagir face à evSay. Je veux aussi que d'autres états puissent réagir à evSay. Mais je ne veux pas que chaque enfant hérite de la réaction de Top à evSay. Vous remarquerez que mon code n'a pas de réaction à evSay dans c1, c2 ou c3. – KitsuneYMG

+0

Donc, vous dites essentiellement que vous transmettez l'evSay mais que vous ne voulez pas vraiment le transmettre? Vous pouvez soit vous défausser, soit accepter que l'avant sera effectivement transmis à la ligne suivante ... – Pieter

+0

voir éditer. Pourquoi pensez-vous que transmettre un événement (evSay) à un état qui ne réagit pas à lui (c1, c2, c3) devrait entraîner l'exécution de la réaction d'un parent? Si les événements qui n'ont pas répondu à remonter la machine, ne devrait pas BUGGY imprimer 4 fois? (un pour le top, un pour chacun de ses 3 enfants qui n'ont pas de réactions) – KitsuneYMG