@@ -44,14 +44,16 @@ MultiThreadedExecutor::~MultiThreadedExecutor() {}
4444void
4545MultiThreadedExecutor::spin ()
4646{
47+ using MutexTwoPriorities = rclcpp::executors::MultiThreadedExecutor::MutexTwoPriorities;
4748 if (spinning.exchange (true )) {
4849 throw std::runtime_error (" spin() called while already spinning" );
4950 }
5051 RCLCPP_SCOPE_EXIT (this ->spinning .store (false ); );
5152 std::vector<std::thread> threads;
5253 size_t thread_id = 0 ;
5354 {
54- std::lock_guard<std::mutex> wait_lock (wait_mutex_);
55+ auto lp_wait_mutex = wait_mutex_.lp ();
56+ std::lock_guard<MutexTwoPriorities::LpMutex> wait_lock (lp_wait_mutex);
5557 for (; thread_id < number_of_threads_ - 1 ; ++thread_id) {
5658 auto func = std::bind (&MultiThreadedExecutor::run, this , thread_id);
5759 threads.emplace_back (func);
@@ -73,10 +75,12 @@ MultiThreadedExecutor::get_number_of_threads()
7375void
7476MultiThreadedExecutor::run (size_t )
7577{
78+ using MutexTwoPriorities = rclcpp::executors::MultiThreadedExecutor::MutexTwoPriorities;
7679 while (rclcpp::ok (this ->context_ ) && spinning.load ()) {
7780 rclcpp::AnyExecutable any_exec;
7881 {
79- std::lock_guard<std::mutex> wait_guard{wait_mutex_};
82+ auto lp_wait_mutex = wait_mutex_.lp ();
83+ std::lock_guard<MutexTwoPriorities::LpMutex> wait_lock (lp_wait_mutex);
8084 if (!rclcpp::ok (this ->context_ ) || !spinning.load ()) {
8185 return ;
8286 }
@@ -85,13 +89,6 @@ MultiThreadedExecutor::run(size_t)
8589 }
8690 if (any_exec.timer ) {
8791 // Guard against multiple threads getting the same timer.
88-
89- // THIS MUST BE DONE WITH BOTH THE WAIT_MUTEX AND SCHEDULED TIMERS MUTEX TAKEN!!
90- // It might seem unnecessary, but you avoid the following race:
91- // Thread A: get timer, context switch.
92- // Thread B: get timer, insert scheduled timer, execute timer, remove scheduled timer.
93- // Thread A: execute timer.
94- std::lock_guard<std::mutex> scheduled_timers_guard{scheduled_timers_mutex_};
9592 if (scheduled_timers_.count (any_exec.timer ) != 0 ) {
9693 // Make sure that any_exec's callback group is reset before
9794 // the lock is released.
@@ -110,15 +107,8 @@ MultiThreadedExecutor::run(size_t)
110107 execute_any_executable (any_exec);
111108
112109 if (any_exec.timer ) {
113- // DON'T DELETE THE scheduled_timers_mutex_ AND REPLACE IT WITH THE wait_mutex_ here.
114- // Now, this mutex will only compete with ONE worker thread that's is trying to insert
115- // a timer.
116- // (and also, N other worker threads also trying to delete a timer).
117- // If the wait_mutex_ is used here, this will compete with all the other worker threads!!!
118- // If we're waiting too long too remove the scheduled timer, maybe we are discarding a timer
119- // execution that we shouldn't!
120- // Of course, this can still happen if the callback is too long ...
121- std::lock_guard<std::mutex> scheduled_timers_guard{scheduled_timers_mutex_};
110+ auto hp_wait_mutex = wait_mutex_.hp ();
111+ std::lock_guard<MutexTwoPriorities::HpMutex> wait_lock (hp_wait_mutex);
122112 auto it = scheduled_timers_.find (any_exec.timer );
123113 if (it != scheduled_timers_.end ()) {
124114 scheduled_timers_.erase (it);
0 commit comments