从一个状态内的自定义函数(不是Action)中提升MSM调用process_event?

时间:2017-03-22 01:38:54

标签: c++ multithreading boost

我正在尝试使用std::thread在使用Boost MSM库编码的状态机中实现并行行为。我正在使用std::thread从状态on_entry的{​​{1}}方法启动线程,我想知道如何调用A方法从内部触发事件那个帖子。这是一个最小的工作示例:

process_event

我的问题是评论#include <iostream> #include <thread> #include <unistd.h> #include <boost/msm/back/state_machine.hpp> #include <boost/msm/front/state_machine_def.hpp> #include <boost/msm/front/functor_row.hpp> namespace msm = boost::msm; namespace msmf = boost::msm::front; namespace mpl = boost::mpl; // Events struct timeout {}; struct outer_:msmf::state_machine_def<outer_> { struct inner_:msmf::state_machine_def<inner_> { template <class Event, class Fsm> void on_entry(Event const&, Fsm&) { std::cout << "[state machine entry] inner" << std::endl; } struct A:msmf::state<> { template <class Event, class Fsm> void on_entry(Event const&, Fsm& f) { std::cout << "[state entry] A" << std::endl; stop_threads_ = false; thread_ = new std::thread(&A::func,this); } template <class Event, class Fsm> void on_exit(Event const&, Fsm&) { stop_threads_ = true; thread_->join(); // wait for threads to finish delete thread_; std::cout << "[state exit] A" << std::endl; } void func() { while (!stop_threads_) { usleep(1000000); std::cout << "Hello" << std::endl; // QUESTION: how to call process_event(timeout()) here? } } public: std::thread* thread_; bool stop_threads_; }; struct Action { template <class Event, class Fsm, class SourceState, class TargetState> void operator()(Event const&, Fsm&, SourceState&, TargetState&) { std::cout << "Trying again..." << std::endl; } }; typedef A initial_state; struct transition_table:mpl::vector< msmf::Row <A,timeout,A,Action> > {}; }; typedef msm::back::state_machine<inner_> inner; typedef inner initial_state; }; typedef msm::back::state_machine<outer_> outer; void waiting_thread() { while(true) { usleep(2000000); } } int main() { outer sm; sm.start(); std::thread wait(waiting_thread); wait.join(); } ,我想要一种方法来执行// QUESTION...方法。谢谢你的帮助!

1 个答案:

答案 0 :(得分:1)

不幸的是,你做不到。

以下是尝试处理func()中的事件的代码。 这是与Boost MSM parallel behavior with delayed self-transitions?

类似的策略

它成功完成。但我有一个例外。

#include <iostream>
#include <thread>
#include <mutex>
#include <unistd.h>

#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>

namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;

// Events
struct timeout {};

struct outer_:msmf::state_machine_def<outer_> {
  std::mutex mtx;
  typedef msm::back::state_machine<outer_> outer;
  std::weak_ptr<outer> wp;

  static std::shared_ptr<outer> create() {
    auto p = std::make_shared<outer>();
    p->wp = p; // set wp after creation.
    return p;
  }

  template <typename Ev>
  void process(Ev&& ev) {
    // process_event via backend weak_ptr
    std::lock_guard<std::mutex> g(wp.lock()->mtx);
    wp.lock()->process_event(std::forward<Ev>(ev));
  }
  struct inner_:msmf::state_machine_def<inner_> {
    std::weak_ptr<outer> wp;

    template <class Event, class Fsm>
    void on_entry(Event const&, Fsm& f) {
      std::cout << "[state machine entry] inner" << std::endl;
      wp = f.wp;
    }
    struct A:msmf::state<> {
      template <class Event, class Fsm>
      void on_entry(Event const&, Fsm& f) {
        std::cout << "[state entry] A" << std::endl;
        stop_threads_ = false;
        thread_ = new std::thread(&A::func,this, std::ref(f));
      }
      template <class Event, class Fsm>
      void on_exit(Event const&, Fsm&) {
        stop_threads_ = true;
        thread_->join(); // wait for threads to finish
        delete thread_;
        std::cout << "[state exit] A" << std::endl;
      }
      void func(inner_& f) {
        while (!stop_threads_) {
          usleep(1000000);
          std::cout << "Hello" << std::endl;
          // QUESTION: how to call process_event(timeout()) here?
          f.wp.lock()->process(timeout());
        }
      }
     public:
      std::thread* thread_;
      bool stop_threads_;
    };
    struct Action {
      template <class Event, class Fsm, class SourceState, class TargetState>
      void operator()(Event const&, Fsm&, SourceState&, TargetState&) {
        std::cout << "Trying again..." << std::endl;
      }
    };
    typedef A initial_state;
    struct transition_table:mpl::vector<
        msmf::Row <A,timeout,A,Action>
    > {};
    template <class FSM,class Event>
    void exception_caught (Event const&,FSM&,std::exception& e) {
        std::cout << e.what() << std::endl;
    }
  };
  typedef msm::back::state_machine<inner_> inner;
  typedef inner initial_state;
  template <class FSM,class Event>
  void exception_caught (Event const&,FSM&,std::exception& e) {
      std::cout << e.what() << std::endl;
  }
};

void waiting_thread() {
  while(true) {
    usleep(2000000);
  }
}

int main() {
  std::shared_ptr<outer_::outer> sm = outer_::create();
  sm->start();
  std::cout << "started" << std::endl;
  std::thread wait(waiting_thread);
  wait.join();
  std::cout << "joined" << std::endl;
}

我添加了异常打印功能如下。 Boost.MSM在exception_caught期间捕获异常时会调用process_event

    template <class FSM,class Event>
    void exception_caught (Event const&,FSM&,std::exception& e) {
        std::cout << e.what() << std::endl;
    }

我得到的信息是Resource deadlock avoided。它最初是由pthread库引起的。如果您创建一个线程然后从不同的线程加入该线程,则抛出该异常。

让我们看看代码创建线程的位置。

以下是重点:

      template <class Event, class Fsm>
      void on_entry(Event const&, Fsm& f) {
        std::cout << "[state entry] A" << std::endl;
        stop_threads_ = false;
        thread_ = new std::thread(&A::func,this, std::ref(f));
      }

从主线程调用它。因为它是从sm->start()调用的。

然后让我们检查加入点/

以下是重点:

      template <class Event, class Fsm>
      void on_exit(Event const&, Fsm&) {
        stop_threads_ = true;
        thread_->join(); // wait for threads to finish
        delete thread_;
        std::cout << "[state exit] A" << std::endl;
      }

f.wp.lock()->process(timeout()); void func(inner_& f)调用。而func是由thread_ = new std::thread(&A::func,this, std::ref(f));创建的线程的入口点。 这意味着thread_->join();正在等待自己。

这就是抛出Resource deadlock avoided的原因。

修改

这是评论的答案 Boost MSM call process_event from a custom function (not an Action) inside a State?

这不是一个完整的解决方案,但可能是设计的暗示。

如果我分离线程并删除join(),则程序按预期工作。当然detach()不是最好的解决方案。而且thread_从未删除过。您需要在产品代码中关注它们。

以下代码的目的是演示状态机行为。

struct A:msmf::state<> {
  template <class Event, class Fsm>
  void on_entry(Event const&, Fsm& f) {
    std::cout << "[state entry] A" << std::endl;
    stop_threads_ = false;
    thread_ = new std::thread(&A::func,this, std::ref(f));
    thread_->detach();
  }
  template <class Event, class Fsm>
  void on_exit(Event const&, Fsm&) {
    stop_threads_ = true;
    std::cout << "[state exit] A" << std::endl;
  }
  struct func {
    func(inner_& f):f(f) {}
      void operator()() {
      while (!stop_threads_) {
        usleep(1000000);
        std::cout << "Hello" << std::endl;
        // QUESTION: how to call process_event(timeout()) here?
        f.wp.lock()->process(timeout());
      }
    }
  };
 public:
  std::thread* thread_;
  bool stop_threads_;
};