Skip to content

Commit 35af6fa

Browse files
committed
Modified the conventional executors (single/multithreaded) to use the infrastructure
proposed in the REP-2017 below. ros-infrastructure/rep#385 Signed-off-by: Shoji Morita <s-morita@esol.co.jp>
1 parent 0e9616a commit 35af6fa

File tree

6 files changed

+335
-66
lines changed

6 files changed

+335
-66
lines changed

rclcpp/include/rclcpp/executor_options.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#ifndef RCLCPP__EXECUTOR_OPTIONS_HPP_
1616
#define RCLCPP__EXECUTOR_OPTIONS_HPP_
1717

18+
#include <string>
19+
1820
#include "rclcpp/context.hpp"
1921
#include "rclcpp/contexts/default_context.hpp"
2022
#include "rclcpp/memory_strategies.hpp"
@@ -36,6 +38,7 @@ struct ExecutorOptions
3638
rclcpp::memory_strategy::MemoryStrategy::SharedPtr memory_strategy;
3739
rclcpp::Context::SharedPtr context;
3840
size_t max_conditions;
41+
std::string name;
3942
};
4043

4144
} // namespace rclcpp

rclcpp/include/rclcpp/executors/multi_threaded_executor.hpp

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,13 @@
2121
#include <vector>
2222
#include <set>
2323
#include <unordered_map>
24+
#include <optional>
2425

25-
#include "rcutils/thread_attr.h"
2626
#include "rclcpp/executor.hpp"
2727
#include "rclcpp/macros.hpp"
2828
#include "rclcpp/memory_strategies.hpp"
2929
#include "rclcpp/visibility_control.hpp"
30+
#include "rcpputils/thread/thread_attribute.hpp"
3031

3132
namespace rclcpp
3233
{
@@ -59,6 +60,21 @@ class MultiThreadedExecutor : public rclcpp::Executor
5960
bool yield_before_execute = false,
6061
std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
6162

63+
RCLCPP_PUBLIC
64+
explicit MultiThreadedExecutor(
65+
size_t number_of_threads,
66+
const rcpputils::ThreadAttribute & thread_attr,
67+
bool yield_before_execute = false,
68+
std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
69+
70+
RCLCPP_PUBLIC
71+
explicit MultiThreadedExecutor(
72+
const rclcpp::ExecutorOptions & options,
73+
size_t number_of_threads,
74+
const rcpputils::ThreadAttribute & thread_attr,
75+
bool yield_before_execute = false,
76+
std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
77+
6278
RCLCPP_PUBLIC
6379
virtual ~MultiThreadedExecutor();
6480

@@ -74,6 +90,16 @@ class MultiThreadedExecutor : public rclcpp::Executor
7490
size_t
7591
get_number_of_threads();
7692

93+
RCLCPP_PUBLIC
94+
const std::optional<rcpputils::ThreadAttribute> &
95+
get_thread_attribute() const
96+
{
97+
return thread_attr_;
98+
}
99+
100+
RCLCPP_PUBLIC
101+
static const char default_name[];
102+
77103
protected:
78104
RCLCPP_PUBLIC
79105
void
@@ -82,11 +108,19 @@ class MultiThreadedExecutor : public rclcpp::Executor
82108
private:
83109
RCLCPP_DISABLE_COPY(MultiThreadedExecutor)
84110

111+
RCLCPP_PUBLIC
112+
explicit MultiThreadedExecutor(
113+
const rclcpp::ExecutorOptions & options,
114+
size_t number_of_threads,
115+
std::optional<rcpputils::ThreadAttribute> thread_attr,
116+
bool yield_before_execute,
117+
std::chrono::nanoseconds timeout);
118+
85119
std::mutex wait_mutex_;
86120
size_t number_of_threads_;
121+
std::optional<rcpputils::ThreadAttribute> thread_attr_;
87122
bool yield_before_execute_;
88123
std::chrono::nanoseconds next_exec_timeout_;
89-
rcutils_thread_attrs_t * thread_attributes_;
90124
};
91125

92126
} // namespace executors

rclcpp/include/rclcpp/executors/single_threaded_executor.hpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@
2121
#include <cstdlib>
2222
#include <memory>
2323
#include <vector>
24+
#include <optional>
2425

25-
#include "rcutils/thread_attr.h"
2626
#include "rclcpp/executor.hpp"
2727
#include "rclcpp/macros.hpp"
2828
#include "rclcpp/memory_strategies.hpp"
2929
#include "rclcpp/node.hpp"
3030
#include "rclcpp/utilities.hpp"
3131
#include "rclcpp/rate.hpp"
3232
#include "rclcpp/visibility_control.hpp"
33+
#include "rcpputils/thread/thread_attribute.hpp"
3334

3435
namespace rclcpp
3536
{
@@ -50,6 +51,11 @@ class SingleThreadedExecutor : public rclcpp::Executor
5051
explicit SingleThreadedExecutor(
5152
const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions());
5253

54+
RCLCPP_PUBLIC
55+
explicit SingleThreadedExecutor(
56+
const rclcpp::ExecutorOptions & options,
57+
const rcpputils::ThreadAttribute & thread_attr);
58+
5359
/// Default destructor.
5460
RCLCPP_PUBLIC
5561
virtual ~SingleThreadedExecutor();
@@ -66,14 +72,31 @@ class SingleThreadedExecutor : public rclcpp::Executor
6672
void
6773
spin() override;
6874

75+
RCLCPP_PUBLIC
76+
bool has_thread_attribute() const
77+
{
78+
return thread_attr_.has_value();
79+
}
80+
81+
RCLCPP_PUBLIC
82+
const std::optional<rcpputils::ThreadAttribute> &
83+
get_thread_attribute() const
84+
{
85+
return thread_attr_;
86+
}
87+
88+
RCLCPP_PUBLIC
89+
static const char default_name[];
90+
6991
protected:
7092
RCLCPP_PUBLIC
7193
void
7294
run();
7395

7496
private:
7597
RCLCPP_DISABLE_COPY(SingleThreadedExecutor)
76-
rcutils_thread_attrs_t * thread_attributes_;
98+
99+
std::optional<rcpputils::ThreadAttribute> thread_attr_;
77100
};
78101

79102
} // namespace executors

rclcpp/src/rclcpp/executors/multi_threaded_executor.cpp

Lines changed: 83 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,50 +14,70 @@
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

2830
using 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+
3037
MultiThreadedExecutor::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()
111122
size_t
112123
MultiThreadedExecutor::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

121128
void
@@ -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

Comments
 (0)