Skip to content

Commit 1b83802

Browse files
Janosch MachowinskiJanosch Machowinski
authored andcommitted
feat(MultiThreadedExecutor): Added ability to handle exceptions from threads
This commit adds external exception handling for the worker threads, allowing application code to implement custom exception handling.
1 parent 93fb466 commit 1b83802

File tree

2 files changed

+49
-3
lines changed

2 files changed

+49
-3
lines changed

rclcpp/include/rclcpp/executors/multi_threaded_executor.hpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,29 @@ class MultiThreadedExecutor : public rclcpp::Executor
6969
void
7070
spin() override;
7171

72+
/**
73+
* \sa rclcpp::Executor:spin() for more details
74+
* \throws std::runtime_error when spin() called while already spinning
75+
* @param exception_handler will be called for every exception in the processing threads
76+
*
77+
* The exception_handler can be called from multiple threads at the same time.
78+
* The exception_handler shall rethrow the exception it if wants to terminate the program.
79+
*/
80+
RCLCPP_PUBLIC
81+
void
82+
spin(std::function<void(const std::exception &)> exception_handler);
83+
7284
RCLCPP_PUBLIC
7385
size_t
7486
get_number_of_threads();
7587

7688
protected:
89+
RCLCPP_PUBLIC
90+
void
91+
run_guarded(
92+
size_t this_thread_number,
93+
std::function<void(const std::exception &)> exception_handler);
94+
7795
RCLCPP_PUBLIC
7896
void
7997
run(size_t this_thread_number);

rclcpp/src/rclcpp/executors/multi_threaded_executor.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ MultiThreadedExecutor::~MultiThreadedExecutor() {}
5151

5252
void
5353
MultiThreadedExecutor::spin()
54+
{
55+
spin(std::function<void(const std::exception &)>());
56+
}
57+
58+
void
59+
MultiThreadedExecutor::spin(std::function<void(const std::exception &)> exception_handler)
5460
{
5561
if (spinning.exchange(true)) {
5662
throw std::runtime_error("spin() called while already spinning");
@@ -61,12 +67,13 @@ MultiThreadedExecutor::spin()
6167
{
6268
std::lock_guard wait_lock{wait_mutex_};
6369
for (; thread_id < number_of_threads_ - 1; ++thread_id) {
64-
auto func = std::bind(&MultiThreadedExecutor::run, this, thread_id);
70+
auto func =
71+
std::bind(&MultiThreadedExecutor::run_guarded, this, thread_id, exception_handler);
6572
threads.emplace_back(func);
6673
}
6774
}
6875

69-
run(thread_id);
76+
run_guarded(thread_id, exception_handler);
7077
for (auto & thread : threads) {
7178
thread.join();
7279
}
@@ -79,7 +86,8 @@ MultiThreadedExecutor::get_number_of_threads()
7986
}
8087

8188
void
82-
MultiThreadedExecutor::run(size_t this_thread_number)
89+
MultiThreadedExecutor::run(
90+
size_t this_thread_number)
8391
{
8492
(void)this_thread_number;
8593
while (rclcpp::ok(this->context_) && spinning.load()) {
@@ -104,3 +112,23 @@ MultiThreadedExecutor::run(size_t this_thread_number)
104112
any_exec.callback_group.reset();
105113
}
106114
}
115+
116+
void
117+
MultiThreadedExecutor::run_guarded(
118+
size_t this_thread_number,
119+
std::function<void(const std::exception &)> exception_handler)
120+
{
121+
if (exception_handler) {
122+
try {
123+
run(this_thread_number);
124+
} catch (const std::exception & e) {
125+
RCLCPP_ERROR_STREAM(
126+
rclcpp::get_logger("rclcpp"),
127+
"Exception while spinning : " << e.what());
128+
129+
exception_handler(e);
130+
}
131+
} else {
132+
run(this_thread_number);
133+
}
134+
}

0 commit comments

Comments
 (0)