我正在尝试使用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...
方法。谢谢你的帮助!
答案 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_;
};