Boost State Machine を使用しようとしていますが、マシンを無限ループで実行しているときにセグメンテーション フォールトが発生しました。基本的に、以下に示すブースト ステート マシン ファンクターの例に同じ例があります。
唯一の違いは、State4 に入るとすぐに "event1" が発生するようになり、ループが作成されることです。これは数千回の反復で機能しますが、その後はセグメント フォールトになります。ある種の UML ルールに違反していて、スタックがオーバーフローしていませんか? 私は基本的に 1 つのブロッキング イベントしか持たず、他のすべての状態を自動的にトリガーして、最終的に State4 にします (実際には、ネットワークからのメッセージを待機しているブロッキング コールになります)。スタックを爆破しないように、Meta State Machine を使用してこれを適切に実装するにはどうすればよいですか?
更新
ここに問題を引き起こしているソースコードを含めました:
http://pastebin.com/fu6rzF0Q
これは基本的に、次の変更を除いて、ファンクター フロント エンドの例です。
「ふりをする」ブロッキング呼び出し機能を追加:
struct BlockingCall {
template <class EVT, class FSM, class SourceState, class TargetState>
void operator()(EVT const &, FSM &, SourceState &, TargetState &) {
std::cout << "my_machine::Waiting for a thing to happen..." << std::endl;
// Pretend I'm actually waiting for something
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "my_machine::OMG the the thing happened!" << std::endl;
}
};
また、遷移表の最後の行も更新しました。
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
Row < State1 , none , State2 >,
Row < State2 , none , State3 , State2ToState3 >,
Row < State3 , none , State4 , none , always_false >,
// +---------+-------------+---------+---------------------+----------------------+
Row < State3 , none , State4 , State3ToState4 , always_true >,
Row < State4 , none , State1 , BlockingCall >
// +---------+-------------+---------+---------------------+----------------------+
> {};
State4 から State1 に移行するためにトリガーする必要があるイベントがなくなったことに注意してください。このコードにより、間違いなくセグ フォールトが発生し、数千行に及ぶスタック トレースが生成されます。
また、待機時間に関係なく、最終的には常にセグフォルトになることにも注意してください。スリープを 1 ~ 100 に変更して遊んでみましたが、最終的には死んでしまいます。単一のループが完了したら、スタックを展開する何らかの方法が必要だと思います。
UPDATE 2 したがって、無限ループでイベントをトリガーすると、エラーが発生しないことがわかりました。これが私がしたことです:
最初に、遷移テーブルを元の例に戻します。
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------+-------------+---------+---------------------+----------------------+
Row < State1 , none , State2 >,
Row < State2 , none , State3 , State2ToState3 >,
Row < State3 , none , State4 , none , always_false >,
// +---------+-------------+---------+---------------------+----------------------+
Row < State3 , none , State4 , State3ToState4 , always_true >,
Row < State4 , event1 , State1 , none >
// +---------+-------------+---------+---------------------+----------------------+
> {};
次に、メインプログラムを次のように変更しました。
void test() {
my_machine p;
// needed to start the highest-level SM. This will call on_entry and mark the
// start of the SM
// in this case it will also immediately trigger all anonymous transitions
p.start();
// this event will bring us back to the initial state and thus, a new "loop"
// will be started
while (true) {
p.process_event(event1());
}
}
そして今、私は全速力で (スリープなしで) 実行しており、セグ フォールトも発生していません。これに基づいて、ステート マシンを起動し、内部イベントを実行して処理する方法はないようですが、正しいですか? 私は常に、少なくとも偶数でトリガーされるプロセスを外側に持つ必要がありますか?
更新 3
最終的に私の目標は、次の図のようなものを実装することです。
私の意図は、ステート マシンを開始することであり、それ以上の介入なしに着信メッセージを待つだけです。