1414
1515#include " rclcpp/executors/multi_threaded_executor.hpp"
1616
17+ #include < algorithm>
1718#include < chrono>
1819#include < functional>
1920#include < memory>
21+ #include < optional>
2022#include < vector>
2123
2224#include " rcpputils/scope_exit.hpp"
23- #include " rcpputils/threads .hpp"
25+ #include " rcpputils/thread .hpp"
2426
2527#include " rclcpp/logging.hpp"
2628#include " rclcpp/utilities.hpp"
2729
2830using rclcpp::executors::MultiThreadedExecutor;
2931
32+ const char MultiThreadedExecutor::default_name[] = " RCLCPP_EXECUTOR_MULTI_THREADED" ;
33+
34+ static std::optional<rcpputils::ThreadAttribute>
35+ default_thread_attr (const rclcpp::ExecutorOptions & options);
36+
3037MultiThreadedExecutor::MultiThreadedExecutor (
3138 const rclcpp::ExecutorOptions & options,
3239 size_t number_of_threads,
3340 bool yield_before_execute,
3441 std::chrono::nanoseconds next_exec_timeout)
42+ : MultiThreadedExecutor(
43+ options, number_of_threads, default_thread_attr(options),
44+ yield_before_execute, next_exec_timeout) {}
45+
46+ MultiThreadedExecutor::MultiThreadedExecutor (
47+ size_t number_of_threads,
48+ rcpputils::ThreadAttribute const & thread_attr,
49+ bool yield_before_execute,
50+ std::chrono::nanoseconds next_exec_timeout)
51+ : MultiThreadedExecutor(
52+ rclcpp::ExecutorOptions (), number_of_threads, std::optional(thread_attr),
53+ yield_before_execute, next_exec_timeout) {}
54+
55+ MultiThreadedExecutor::MultiThreadedExecutor (
56+ const rclcpp::ExecutorOptions & options,
57+ size_t number_of_threads,
58+ rcpputils::ThreadAttribute const & thread_attr,
59+ bool yield_before_execute,
60+ std::chrono::nanoseconds next_exec_timeout)
61+ : MultiThreadedExecutor(
62+ options, number_of_threads, std::optional(thread_attr),
63+ yield_before_execute, next_exec_timeout) {}
64+
65+ MultiThreadedExecutor::MultiThreadedExecutor (
66+ const rclcpp::ExecutorOptions & options,
67+ size_t number_of_threads,
68+ std::optional<rcpputils::ThreadAttribute> thread_attr,
69+ bool yield_before_execute,
70+ std::chrono::nanoseconds next_exec_timeout)
3571: rclcpp::Executor(options),
72+ thread_attr_(std::move(thread_attr)),
3673 yield_before_execute_(yield_before_execute),
37- next_exec_timeout_(next_exec_timeout),
38- thread_attributes_(nullptr )
74+ next_exec_timeout_(next_exec_timeout)
3975{
40- bool has_number_of_threads_arg = number_of_threads > 0 ;
41-
4276 number_of_threads_ = number_of_threads > 0 ?
4377 number_of_threads :
4478 std::max (rcpputils::Thread::hardware_concurrency (), 2U );
4579
46- if (rcutils_thread_attrs_t * attrs = rcl_context_get_thread_attrs (
47- options.context ->get_rcl_context ().get ()))
48- {
49- thread_attributes_ = attrs;
50- }
51-
52- if (has_number_of_threads_arg && thread_attributes_ &&
53- thread_attributes_->num_attributes != number_of_threads)
54- {
55- RCLCPP_WARN (
56- rclcpp::get_logger (" rclcpp" ),
57- " The number of threads argument passed to the MultiThreadedExecutor"
58- " is different from the number of thread attributes.\n "
59- " The executor runs using the thread attributes and ignores the former." );
60- } else if (number_of_threads_ == 1 ) {
80+ if (number_of_threads_ == 1 ) {
6181 RCLCPP_WARN (
6282 rclcpp::get_logger (" rclcpp" ),
6383 " MultiThreadedExecutor is used with a single thread.\n "
@@ -77,21 +97,12 @@ MultiThreadedExecutor::spin()
7797 std::vector<rcpputils::Thread> threads;
7898 size_t thread_id = 0 ;
7999
80- if (thread_attributes_) {
81- rcpputils::Thread::Attribute thread_attr;
82- {
83- std::lock_guard wait_lock{wait_mutex_};
84- for (; thread_id < thread_attributes_->num_attributes - 1 ; ++thread_id) {
85- thread_attr.set_thread_attribute (
86- thread_attributes_->attributes [thread_id]);
87- auto func = std::bind (&MultiThreadedExecutor::run, this , thread_id);
88- threads.emplace_back (rcpputils::Thread (thread_attr, func));
89- }
100+ if (thread_attr_) {
101+ std::lock_guard wait_lock{wait_mutex_};
102+ for (; thread_id < number_of_threads_; ++thread_id) {
103+ auto func = std::bind (&MultiThreadedExecutor::run, this , thread_id);
104+ threads.emplace_back (thread_attr_.value (), func);
90105 }
91- thread_attr.set_thread_attribute (
92- thread_attributes_->attributes [thread_id]);
93- rcpputils::this_thread::run_with_thread_attribute (
94- thread_attr, &MultiThreadedExecutor::run, this , thread_id);
95106 } else {
96107 {
97108 std::lock_guard wait_lock{wait_mutex_};
@@ -111,11 +122,7 @@ MultiThreadedExecutor::spin()
111122size_t
112123MultiThreadedExecutor::get_number_of_threads ()
113124{
114- if (thread_attributes_) {
115- return thread_attributes_->num_attributes ;
116- } else {
117- return number_of_threads_;
118- }
125+ return number_of_threads_;
119126}
120127
121128void
@@ -144,3 +151,40 @@ MultiThreadedExecutor::run(size_t this_thread_number)
144151 any_exec.callback_group .reset ();
145152 }
146153}
154+
155+ std::optional<rcpputils::ThreadAttribute>
156+ default_thread_attr (rclcpp::ExecutorOptions const & options)
157+ {
158+ const rcutils_thread_attrs_t * attrs = rcl_context_get_thread_attrs (
159+ options.context ->get_rcl_context ().get ());
160+ if (!attrs) {
161+ return std::nullopt ;
162+ }
163+
164+ std::string name;
165+ bool name_specified = !options.name .empty ();
166+ if (name_specified) {
167+ name = options.name ;
168+ } else {
169+ name = MultiThreadedExecutor::default_name;
170+ }
171+
172+ const rcutils_thread_attr_t * attrs_beg = attrs->attributes ;
173+ const rcutils_thread_attr_t * attrs_end = attrs->attributes + attrs->num_attributes ;
174+ const rcutils_thread_attr_t * attr = std::find_if (
175+ attrs_beg, attrs_end,
176+ [&](const auto & attr) {
177+ return attr.name == name;
178+ });
179+ if (attr != attrs_end) {
180+ return rcpputils::ThreadAttribute (*attr);
181+ } else {
182+ if (name_specified) {
183+ RCLCPP_WARN (
184+ rclcpp::get_logger (" rclcpp" ),
185+ " MultiThreadedExecutor is named \" %s\" , but not found corresponding thread attribute." ,
186+ name.c_str ());
187+ }
188+ return std::nullopt ;
189+ }
190+ }
0 commit comments