Boost.SML-违反内存保护/分段错误

时间:2019-01-04 13:30:02

标签: c++ boost state-machine boost-sml

程序返回“ 分段错误(核心已转储)”。怎么了?

该实现基于示例-BOOST.SML表单文档中的“ 嵌套”:

http://boost-experimental.github.io/sml/examples/index.html#nested

SM 用于从服务器调用方法。 服务器用于切换SM中的状态。

#include <boost/sml.hpp>
#include <iostream>
namespace sml = boost::sml;
using namespace std;

template <class = class Dummy>
class Server
{
struct pollEvent{};
struct msgRcdEvent{};

class States
{
public:
 States(Server *server): _server(server){}

auto operator()() const noexcept
{
  auto msgRcdAction = [this] {
  std::cout << "HB server -> msgRcdAction " << std::endl;
 _server->recvMsg();
};

auto pollAction = [this] {
 std::cout << "HB server -> pollAction " << std::endl;
  _server->poll();
};

using namespace sml;

return make_transition_table(
 *"idle"_s + event<pollEvent> / pollAction    = "Poll"_s,
 "Poll"_s + event<msgRcdEvent> / msgRcdAction = "RcdMsg"_s,
 "RcdMsg"_s + event<pollEvent> / pollAction   = "Poll"_s
);
}
private:
 Server *_server{nullptr};
};

public:
 Server()
 {
  _states = new States(this);
  _sm     = new sml::sm<States>(*_states);
 }

 void process(){_sm->process_event(pollEvent{});}
 void poll(){_sm->process_event(msgRcdEvent{});}
 void recvMsg(){_sm->process_event(pollEvent{});}

private:
 States *_states{nullptr};
 sml::sm<States> *_sm{nullptr};
};

int main()
{
 Server<> s{};
 s.process();
 return 0;
}

1 个答案:

答案 0 :(得分:0)

分段错误是由堆栈溢出引起的。因为_sm->process_event(...)是递归调用的。该函数立即处理事件。

为了避免这种情况,我们需要对事件机制进行排队,而不是立即处理事件。

sml提供了它。

这是代码。请参阅注释1到3。

#include <boost/sml.hpp>
#include <iostream>
#include <queue>

namespace sml = boost::sml;
using namespace std;

template <class = class Dummy>
class Server
{
    struct pollEvent{};
    struct msgRcdEvent{};

    class States
    {
    public:
        States(Server *server): _server(server){}

        auto operator()() const noexcept
        {
            auto msgRcdAction =
                // 2. Add parameters to lambda expression
                //    The second parameter is process callable object that is from
                //    action. The template argument `pollEvent` is the event you want
                //    to pass to the `process`.
                //    You can write multiple template arguments.
                //    e.g.) sml::back::process<pollEvent, msgRcdEvent>
                [this] (auto const& /*ev*/, sml::back::process<pollEvent> process) {
                    std::cout << "HB server -> msgRcdAction " << std::endl;
                    _server->recvMsg(process);
                };

            auto pollAction =
                [this] (auto const& /*ev*/, sml::back::process<msgRcdEvent> process) {
                    std::cout << "HB server -> pollAction " << std::endl;
                    _server->poll(process);
                };

            using namespace sml;

            return make_transition_table(
                *"idle"_s + event<pollEvent> / pollAction    = "Poll"_s,
                "Poll"_s + event<msgRcdEvent> / msgRcdAction = "RcdMsg"_s,
                "RcdMsg"_s + event<pollEvent> / pollAction   = "Poll"_s
            );
        }
    private:
        Server *_server{nullptr};
    };

public:
    Server()
    {
        _states = new States(this);
        _sm     = new sml::sm<States, sml::process_queue<std::queue>>(*_states);
    }

    void process1(){_sm->process_event(pollEvent{});}

    // 3. Invoke process callable object
    template <typename Process>
    void poll(Process p){ p(msgRcdEvent{});}
    template <typename Process>
    void recvMsg(Process p){ p(pollEvent{});}

private:
    States *_states{nullptr};

    // 1. Add `sml::process_queue<std::queue>` template argument to `sml::sm`.
    sml::sm<States, sml::process_queue<std::queue>> *_sm{nullptr};
};

int main()
{
    Server<> s{};
    s.process1();
    return 0;
}

sml::back::process<pollEvent>(注释2)是使事件排队的可调用对象(类似函数)。您可以调用它而不是_sm->process_event(...)(注释3)。 将该队列设置为sm的模板参数(注释1)。