From 33fc3340778f5fcd5b53e25c1345a25ff537c935 Mon Sep 17 00:00:00 2001 From: peri4 Date: Mon, 5 Aug 2024 23:25:23 +0300 Subject: [PATCH] PIStateMachine::postEvent() now thread-safe and can be recursive --- libs/main/state_machine/pistatemachine.h | 19 ++++++++++++++ main.cpp | 33 +++++++++++++----------- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/libs/main/state_machine/pistatemachine.h b/libs/main/state_machine/pistatemachine.h index 31bb5d8e..51a52f06 100644 --- a/libs/main/state_machine/pistatemachine.h +++ b/libs/main/state_machine/pistatemachine.h @@ -45,11 +45,27 @@ public: template bool postEvent(int event_id, Args... args) { if (!is_running) return false; + if (in_post.exchange(true)) { + PIMutexLocker ml(nested_mutex); + nested_posts.enqueue([this, event_id, args...] { postEvent(event_id, args...); }); + // piCout << "queue nested post"; + return false; + } need_finish = false; PIScopeExitCall exit_call([this] { + in_post = false; if (need_finish) { is_running = false; if (on_finish) on_finish(); + } else { + nested_mutex.lock(); + while (nested_posts.isNotEmpty()) { + auto np = nested_posts.dequeue(); + nested_mutex.unlock(); + np(); + nested_mutex.lock(); + } + nested_mutex.unlock(); } }); PIVector active_states; @@ -71,6 +87,9 @@ private: void onFinish() override; bool is_running = false, need_finish = false; + PIQueue> nested_posts; + PIMutex nested_mutex; + std::atomic_bool in_post = {false}; std::function on_finish; }; diff --git a/main.cpp b/main.cpp index 9c5d61ba..66a38948 100644 --- a/main.cpp +++ b/main.cpp @@ -28,7 +28,7 @@ void tfunc4(int delim) { int main(int argc, char * argv[]) { - PIPackedTCP * tcp_s = + /*PIPackedTCP * tcp_s = PIIODevice::createFromFullPath("ptcp://s::8000")->cast(); // new PIPackedTCP(PIPackedTCP::Server, {"0.0.0.0:8000"}); PIPackedTCP * tcp_c = PIIODevice::createFromFullPath("ptcp://c:127.0.0.1:8000") ->cast(); // new PIPackedTCP(PIPackedTCP::Client, {"127.0.0.1:8000"}); @@ -78,7 +78,7 @@ int main(int argc, char * argv[]) { // piCout << tcp_s->constructFullPath(); delete tcp_s; delete tcp_c; - return 0; + return 0;*/ /*PITimer timer(tfunc); // timer.addDelimiter(2); timer.addDelimiter(40, tfunc4); @@ -100,6 +100,7 @@ int main(int argc, char * argv[]) { PIStateLambda * s1 = new PIStateLambda([] { piCout << "+ enter s1"; }, [] { piCout << "- exit s1"; }, "s1"); PIStateLambda * s2 = new PIStateLambda([] { piCout << "+ enter s2"; }, [] { piCout << "- exit s2"; }, "s2"); PIStateLambda * s3 = new PIStateLambda([] { piCout << "+ enter s3"; }, [] { piCout << "- exit s3"; }, "s3"); + PIStateLambda * s4 = new PIStateLambda([] { piCout << "+ enter s4"; }, [] { piCout << "- exit s4"; }, "s4"); PIStateLambda * s11 = new PIStateLambda([] { piCout << " + enter s11"; }, [] { piCout << " - exit s11"; }, "s11"); PIStateLambda * s12 = new PIStateLambda([] { piCout << " + enter s12"; }, [] { piCout << " - exit s12"; }, "s12"); PIStateLambda * s13 = new PIStateLambda([] { piCout << " + enter s13"; }, [] { piCout << " - exit s13"; }, "s13"); @@ -111,33 +112,35 @@ int main(int argc, char * argv[]) { PIStateLambda * s213 = new PIStateLambda([] { piCout << " + enter s213"; }, [] { piCout << " - exit s213"; }, "s213"); PIStateFinal * s214 = new PIStateFinal([] { piCout << " + enter s214 final"; }, "s214f"); - root->addStates({s1, s2, s3}); - s1->addStates({s11, s12, s13}); - s2->addStates({s21, s22, s23}); - s21->addStates({s211, s212, s213}); - // root->addState(s214); + root->addStates({s1, s2, s3, s4}); + // s1->addStates({s11, s12, s13}); + // s2->addStates({s21, s22, s23}); + // s21->addStates({s211, s212, s213}); + // root->addState(s214); s2->setParallel(true); - root->setInitialState(s2); + root->setInitialState(s1); s1->setInitialState(s11); s2->setInitialState(s21); s21->setInitialState(s213); // s213->addTransition(s13, meVoid)->addAction([] { piCout << "action transition s21 -> s22"; }); // s3->addTransition(s212, meVoid)->addAction([] { piCout << "action transition s1 -> s213"; }); - s2->addTransition(s3, meVoid); - s2->addTimeoutTransition(s3, .5_s); - // s3->addTransition(s1, meIntString)->addGuard([](int i, PIString str) { return i == 2 && str == "hello"; }); + s1->addTransition(s2, meVoid)->addAction([root] { root->postEvent(meInt, 1); }); + s2->addTransition(s3, meInt)->addGuard([](int i) { return i == 1; })->addAction([root] { root->postEvent(meInt, 2); }); + s3->addTransition(s4, meInt)->addGuard([](int i) { return i == 2; })->addAction([root] { root->postEvent(meInt, 3); }); + // s2->addTimeoutTransition(s3, .5_s); + // s3->addTransition(s1, meIntString)->addGuard([](int i, PIString str) { return i == 2 && str == "hello"; }); root->start(); piCout << "initial" << root->isRunning() << "\n"; - piCout << "active atomics" << root->activeAtomics(); + // piCout << "active atomics" << root->activeAtomics(); root->print(); - // piCout << "\npost event"; - // posted = root->postEvent(meVoid); - // piCout << "posted" << posted << "\n"; + piCout << "\npost event"; + posted = root->postEvent(meVoid); + piCout << "posted" << posted << "\n"; // piCout << "active atomics" << root->activeAtomics(); piSleep(1.); root->print();