10
10
#include < mutex>
11
11
#include < queue>
12
12
#include < set>
13
+ #include < shared_mutex>
13
14
#include < string>
14
15
#include < unordered_map>
15
16
#include < utility>
@@ -272,21 +273,22 @@ namespace fc::fsm {
272
273
*/
273
274
outcome::result<void > begin (const EntityPtr &entity_ptr,
274
275
StateEnumType initial_state) {
276
+ std::unique_lock lock (states_mutex_);
275
277
auto lookup = states_.find (entity_ptr);
276
278
if (states_.end () != lookup) {
277
279
return FsmError::ENTITY_ALREADY_BEING_TRACKED;
278
280
}
279
- states_[ entity_ptr] = initial_state;
281
+ states_. emplace ( entity_ptr, initial_state) ;
280
282
return outcome::success ();
281
283
}
282
284
283
285
// schedule an event for an object
284
286
outcome::result<void > send (const EntityPtr &entity_ptr,
285
287
EventEnumType event) {
286
- std::lock_guard<std::mutex> lock (mutex_);
287
288
if (not running_) {
288
289
return FsmError::MACHINE_STOPPED;
289
290
}
291
+ std::lock_guard lock (event_queue_mutex_);
290
292
event_queue_.emplace (entity_ptr, event);
291
293
return outcome::success ();
292
294
}
@@ -305,7 +307,7 @@ namespace fc::fsm {
305
307
* @return entity state
306
308
*/
307
309
outcome::result<StateEnumType> get (const EntityPtr &entity_pointer) const {
308
- std::lock_guard<std::mutex> lock (mutex_ );
310
+ std::shared_lock lock (states_mutex_ );
309
311
auto lookup = states_.find (entity_pointer);
310
312
if (states_.end () == lookup) {
311
313
return FsmError::ENTITY_NOT_TRACKED;
@@ -319,13 +321,12 @@ namespace fc::fsm {
319
321
* state
320
322
*/
321
323
std::unordered_map<EntityPtr, StateEnumType> list () const {
322
- std::lock_guard<std::mutex> lock (mutex_ );
324
+ std::shared_lock lock (states_mutex_ );
323
325
return states_;
324
326
}
325
327
326
328
// / Prevent further events processing
327
329
void stop () {
328
- std::lock_guard<std::mutex> lock (mutex_);
329
330
running_ = false ;
330
331
scheduler_handle_.cancel ();
331
332
}
@@ -365,33 +366,45 @@ namespace fc::fsm {
365
366
// / async events processor routine
366
367
void onTimer () {
367
368
EventQueueItem event_pair;
368
- std::lock_guard<std::mutex> lock (mutex_);
369
369
if (not running_) {
370
370
return ;
371
371
}
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 ();
375
381
}
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 ;
382
392
}
383
393
auto event_handler = transitions_.find (event_pair.second );
384
394
if (transitions_.end () == event_handler) {
385
395
return ; // transition from the state by the event is not set
386
396
}
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 );
389
399
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
+ }
391
404
if (any_change_cb_) {
392
405
any_change_cb_.get ()(event_pair.first , // pointer to entity
393
406
event_pair.second , // trigger event
394
- current_state-> second , // source state
407
+ source_state, // source state
395
408
resulting_state.get ()); // destination state
396
409
}
397
410
}
@@ -400,7 +413,7 @@ namespace fc::fsm {
400
413
bool running_; // /< FSM is enabled to process events
401
414
Scheduler::Ticks delay_; // /< minimum async loop delay
402
415
403
- mutable std::mutex mutex_ ;
416
+ std::mutex event_queue_mutex_ ;
404
417
std::queue<EventQueueItem> event_queue_;
405
418
std::shared_ptr<Scheduler> scheduler_;
406
419
Scheduler::Handle scheduler_handle_;
@@ -410,6 +423,7 @@ namespace fc::fsm {
410
423
std::unordered_map<EventEnumType, TransitionRule> transitions_;
411
424
412
425
// / a list of entities' current states
426
+ mutable std::shared_mutex states_mutex_;
413
427
std::unordered_map<EntityPtr, StateEnumType> states_;
414
428
415
429
// / optional callback for any transition
0 commit comments