Почему мое использование контекста <State>(). Method () нарушает утверждение диаграммы состояний? - PullRequest
3 голосов
/ 25 декабря 2010

Я разработал некоторый концептуальный код для проекта, над которым я буду работать в ближайшее время.Проект поддается разработке конечного автомата, и я думаю, что boost :: statechart будет работать хорошо.Однако я столкнулся с препятствиями, когда попытался использовать context ().Вот пример (я рад поставить больше кода, но я думаю, что это важная часть):

struct Wait : fsm::simple_state< Wait, Active > {

  typedef mpl::list<fsm::transition< UnderflowEvent, Exec> > reactions;

 public:
  Wait()
    : m_wait_op() {
    std::cout << "entering wait state." << std::endl;
    wait();
  }
  ~Wait() { std::cout << "exiting wait state." << std::endl; }

 private:
  default_wait m_wait_op;
  fsm::result wait() {
    if(context<Active>().underflow_condition()) {
      m_wait_op();
      return transit<Wait>();
    }
    else if(context<Active>().overflow_condition()) {
      return transit<Exec>();
    }
    else {
      // undefined - keep waiting                                                                                                                                                
    }
  }

};

Состояние Active имеет методы с именем "[over | under] flow_condition", которые просто возвращаютправда на данный момент.Помимо проблем с моим дизайном, я получаю следующую ошибку подтверждения, когда создаю таким образом:

int main(void) {

  Throttler my_throttler;

  my_throttler.initiate();

  return 0;

}

и вот утверждение:

утверждение "get_pointer (stt.pContext_)!= 0 "не удалось

Я посмотрел это утверждение в файле" /usr/include/boost/statechart/simple_state.hpp ", строка 689 (повышение 1.45), и в комментариях говорится, что оно естьне позволяйте simple_state использовать контексты.Это озадачило меня, когда я вернулся к примеру с секундомером и увидел, что этот пример делает именно то, что я пытался сделать.Поэтому я скомпилировал его, и это неудивительно, что это утверждение не нарушается кодом секундомера.Я что-то пропустил?Может быть, есть что-то еще в коде, который я пропустил?Вот весь заголовок (пожалуйста, помните, что это концептуальный код ... Я не буду выпускать его на волю, пока он не будет полностью обобщен):

    #ifndef _THROTTLER_H_
#define _THROTTLER_H_

#include<queue>
#include<vector>
#include<ctime>

#include<boost/statechart/event.hpp>
#include<boost/statechart/transition.hpp>
#include<boost/statechart/state_machine.hpp>
#include<boost/statechart/simple_state.hpp>

#include<boost/mpl/list.hpp>

#include<iostream>


namespace mpl = boost::mpl;
namespace fsm = boost::statechart;

namespace {

  unsigned int DEFAULT_WAIT_TIME(1000);

}

struct noop {
public:

  noop() { m_priority = (1 << sizeof(int)); }
  noop(unsigned int priority) { m_priority = priority; }
  virtual ~noop() {}

  bool operator()(void) {
    return true;
  }
  friend bool operator<(noop a, noop b);

private:
  unsigned int m_priority;
};



bool operator<(noop a, noop b) {
  return a.m_priority < b.m_priority;
}

struct compare_noops {
  bool operator()(noop a, noop b) {
  }
};


struct default_wait {
  void operator()(unsigned long msecs = DEFAULT_WAIT_TIME) {
    std::clock_t endtime =
      std::clock() + (msecs*1000*CLOCKS_PER_SEC);
    while(clock() < endtime);
  }
};



struct OverflowEvent : fsm::event< OverflowEvent > {};
struct UnderflowEvent : fsm::event< UnderflowEvent > {};
struct ResetEvent : fsm::event< ResetEvent > {};

struct Active;
struct Throttler : fsm::state_machine< Throttler, Active > {};

struct Wait;
struct Active : fsm::simple_state< Active, Throttler, Wait > {

 public:

  typedef mpl::list<fsm::transition< ResetEvent, Active> > reactions;

  bool overflow_condition(void) { return true; }
  bool underflow_condition(void) { return true; }

  void queue_operation(noop op) {
    m_operation_queue.push(op);
  }
  void perform_operation(void) {
    noop op(m_operation_queue.top());
    if(op())
      m_operation_queue.pop();
    else
      throw;
  }

 private:

  std::priority_queue<noop, std::vector<noop>, compare_noops > m_operation_queue;
 private:

  std::priority_queue<noop, std::vector<noop>, compare_noops > m_operation_queue;

};

struct Exec : fsm::simple_state< Exec, Active > {

  typedef mpl::list<fsm::transition< OverflowEvent, Wait> > reactions;

  Exec() { std::cout << "entering exec state." << std::endl; }
  ~Exec() { std::cout << "exiting exec state." << std::endl; }

};

struct Wait : fsm::simple_state< Wait, Active > {

  typedef mpl::list<fsm::transition< UnderflowEvent, Exec> > reactions;

 public:
  Wait()
    : m_wait_op() {
    std::cout << "entering wait state." << std::endl;
    wait();
  }
  ~Wait() { std::cout << "exiting wait state." << std::endl; }

 private:
  default_wait m_wait_op;
  fsm::result wait() {
    if(context<Active>().underflow_condition()) {
      m_wait_op();
      return transit<Wait>();
    }
    else if(context<Active>().overflow_condition()) {
      return transit<Exec>();
    }
    else {
      // undefined - keep waiting                                                                                                                                                
    }
  }

};


#endif

1 Ответ

3 голосов
/ 30 июня 2011

Как вы отметили в своем комментарии, это связано с попыткой доступа к внешнему контексту из конструктора, что недопустимо для simple_state.

С simple_state.hpp:

  // This assert fails when an attempt is made to access the state machine
  // from a constructor of a state that is *not* a subtype of state<>.
  // To correct this, derive from state<> instead of simple_state<>.
  BOOST_ASSERT( get_pointer( pContext_ ) != 0 );

Таким образом, вы сможете получить доступ к внешнему контексту из конструктора, если будете основывать свои состояния на классе state (а не на simple_state).

Тем не менее, я 'Я не уверен, какое влияние это может оказать на ваши штаты.Если этот вопрос получит ответ, он также может быть полезен для вас (:

Из того, что я понимаю, вам нужно изменить Wait, чтобы получить из state:

 struct Wait : fsm::state< Wait, Active > {

и затем измените конструктор Wait() на что-то вроде

typedef fsm::state< Wait, Active > my_base;
Wait( my_context ctx ) : my_base( ctx )
// and any other pre-constructor initialisation...

Тип my_context определен (защищен) в state<> и должен быть передан виз конструктора производного класса.

...