Skip to content

Commit 281c71d

Browse files
add 2nd mutex for fsm states synchronization (#204)
Signed-off-by: Alexey-N-Chernyshov <[email protected]>
1 parent d7f21ea commit 281c71d

File tree

1 file changed

+34
-20
lines changed

1 file changed

+34
-20
lines changed

core/fsm/fsm.hpp

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <mutex>
1111
#include <queue>
1212
#include <set>
13+
#include <shared_mutex>
1314
#include <string>
1415
#include <unordered_map>
1516
#include <utility>
@@ -272,21 +273,22 @@ namespace fc::fsm {
272273
*/
273274
outcome::result<void> begin(const EntityPtr &entity_ptr,
274275
StateEnumType initial_state) {
276+
std::unique_lock lock(states_mutex_);
275277
auto lookup = states_.find(entity_ptr);
276278
if (states_.end() != lookup) {
277279
return FsmError::ENTITY_ALREADY_BEING_TRACKED;
278280
}
279-
states_[entity_ptr] = initial_state;
281+
states_.emplace(entity_ptr, initial_state);
280282
return outcome::success();
281283
}
282284

283285
// schedule an event for an object
284286
outcome::result<void> send(const EntityPtr &entity_ptr,
285287
EventEnumType event) {
286-
std::lock_guard<std::mutex> lock(mutex_);
287288
if (not running_) {
288289
return FsmError::MACHINE_STOPPED;
289290
}
291+
std::lock_guard lock(event_queue_mutex_);
290292
event_queue_.emplace(entity_ptr, event);
291293
return outcome::success();
292294
}
@@ -305,7 +307,7 @@ namespace fc::fsm {
305307
* @return entity state
306308
*/
307309
outcome::result<StateEnumType> get(const EntityPtr &entity_pointer) const {
308-
std::lock_guard<std::mutex> lock(mutex_);
310+
std::shared_lock lock(states_mutex_);
309311
auto lookup = states_.find(entity_pointer);
310312
if (states_.end() == lookup) {
311313
return FsmError::ENTITY_NOT_TRACKED;
@@ -319,13 +321,12 @@ namespace fc::fsm {
319321
* state
320322
*/
321323
std::unordered_map<EntityPtr, StateEnumType> list() const {
322-
std::lock_guard<std::mutex> lock(mutex_);
324+
std::shared_lock lock(states_mutex_);
323325
return states_;
324326
}
325327

326328
/// Prevent further events processing
327329
void stop() {
328-
std::lock_guard<std::mutex> lock(mutex_);
329330
running_ = false;
330331
scheduler_handle_.cancel();
331332
}
@@ -365,33 +366,45 @@ namespace fc::fsm {
365366
/// async events processor routine
366367
void onTimer() {
367368
EventQueueItem event_pair;
368-
std::lock_guard<std::mutex> lock(mutex_);
369369
if (not running_) {
370370
return;
371371
}
372-
if (event_queue_.empty()) {
373-
scheduler_handle_.reschedule(kSlowModeDelayMs);
374-
return;
372+
{
373+
std::lock_guard lock(event_queue_mutex_);
374+
if (event_queue_.empty()) {
375+
scheduler_handle_.reschedule(kSlowModeDelayMs);
376+
return;
377+
}
378+
scheduler_handle_.reschedule(0);
379+
event_pair = event_queue_.front();
380+
event_queue_.pop();
375381
}
376-
scheduler_handle_.reschedule(0);
377-
event_pair = event_queue_.front();
378-
event_queue_.pop();
379-
auto current_state = states_.find(event_pair.first);
380-
if (states_.end() == current_state) {
381-
return; // entity is not tracked
382+
383+
StateEnumType source_state;
384+
{
385+
std::shared_lock lock(states_mutex_);
386+
auto current_state = states_.find(event_pair.first);
387+
if (states_.end() == current_state) {
388+
return; // entity is not tracked
389+
}
390+
// copy to prevent invalidation of iterator
391+
source_state = current_state->second;
382392
}
383393
auto event_handler = transitions_.find(event_pair.second);
384394
if (transitions_.end() == event_handler) {
385395
return; // transition from the state by the event is not set
386396
}
387-
auto resulting_state = event_handler->second.dispatch(
388-
current_state->second, event_pair.first);
397+
auto resulting_state =
398+
event_handler->second.dispatch(source_state, event_pair.first);
389399
if (resulting_state) {
390-
states_[event_pair.first] = resulting_state.get();
400+
{
401+
std::unique_lock lock(states_mutex_);
402+
states_[event_pair.first] = resulting_state.get();
403+
}
391404
if (any_change_cb_) {
392405
any_change_cb_.get()(event_pair.first, // pointer to entity
393406
event_pair.second, // trigger event
394-
current_state->second, // source state
407+
source_state, // source state
395408
resulting_state.get()); // destination state
396409
}
397410
}
@@ -400,7 +413,7 @@ namespace fc::fsm {
400413
bool running_; ///< FSM is enabled to process events
401414
Scheduler::Ticks delay_; ///< minimum async loop delay
402415

403-
mutable std::mutex mutex_;
416+
std::mutex event_queue_mutex_;
404417
std::queue<EventQueueItem> event_queue_;
405418
std::shared_ptr<Scheduler> scheduler_;
406419
Scheduler::Handle scheduler_handle_;
@@ -410,6 +423,7 @@ namespace fc::fsm {
410423
std::unordered_map<EventEnumType, TransitionRule> transitions_;
411424

412425
/// a list of entities' current states
426+
mutable std::shared_mutex states_mutex_;
413427
std::unordered_map<EntityPtr, StateEnumType> states_;
414428

415429
/// optional callback for any transition

0 commit comments

Comments
 (0)