diff --git a/rclcpp/include/rclcpp/context.hpp b/rclcpp/include/rclcpp/context.hpp index 1251e58b62..cb7786579d 100644 --- a/rclcpp/include/rclcpp/context.hpp +++ b/rclcpp/include/rclcpp/context.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -365,6 +366,7 @@ class Context : public std::enable_shared_from_this std::shared_ptr rcl_context_; rclcpp::InitOptions init_options_; std::string shutdown_reason_; + std::atomic is_shutting_down_{false}; // Keep shared ownership of the global logging mutex. std::shared_ptr logging_mutex_; diff --git a/rclcpp/src/rclcpp/context.cpp b/rclcpp/src/rclcpp/context.cpp index 33bd0bf0b9..7db3b1e3f2 100644 --- a/rclcpp/src/rclcpp/context.cpp +++ b/rclcpp/src/rclcpp/context.cpp @@ -299,6 +299,12 @@ Context::shutdown_reason() const bool Context::shutdown(const std::string & reason) { + // Prevent double-shutdown: the signal handler thread and the main thread + // may both call shutdown() during Ctrl-C. Use an atomic flag to ensure + // only the first call proceeds; subsequent calls return immediately. + if (is_shutting_down_.exchange(true)) { + return false; + } // prevent races std::lock_guard init_lock(init_mutex_); // ensure validity