Skip to content

Commit 4d355bb

Browse files
committed
use weak_ptr to simplify SubscribersRegistry in RosTopicSubNode
1 parent b732819 commit 4d355bb

File tree

1 file changed

+30
-44
lines changed

1 file changed

+30
-44
lines changed

behaviortree_ros2/include/behaviortree_ros2/bt_topic_sub_node.hpp

Lines changed: 30 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -51,24 +51,7 @@ class RosTopicSubNode : public BT::ConditionNode
5151
protected:
5252
struct SubscriberInstance
5353
{
54-
void init(std::shared_ptr<rclcpp::Node> node, const std::string& topic_name)
55-
{
56-
// create a callback group for this particular instance
57-
callback_group = node->create_callback_group(
58-
rclcpp::CallbackGroupType::MutuallyExclusive, false);
59-
callback_group_executor.add_callback_group(callback_group,
60-
node->get_node_base_interface());
61-
62-
rclcpp::SubscriptionOptions option;
63-
option.callback_group = callback_group;
64-
65-
// The callback will broadcast to all the instances of RosTopicSubNode<T>
66-
auto callback = [this](const std::shared_ptr<TopicT> msg) {
67-
last_msg = msg;
68-
broadcaster(msg);
69-
};
70-
subscriber = node->create_subscription<TopicT>(topic_name, 1, callback, option);
71-
}
54+
SubscriberInstance(std::shared_ptr<rclcpp::Node> node, const std::string& topic_name);
7255

7356
std::shared_ptr<Subscriber> subscriber;
7457
rclcpp::CallbackGroup::SharedPtr callback_group;
@@ -83,12 +66,13 @@ class RosTopicSubNode : public BT::ConditionNode
8366
return sub_mutex;
8467
}
8568

69+
using SubscribersRegistry =
70+
std::unordered_map<std::string, std::weak_ptr<SubscriberInstance>>;
71+
8672
// contains the fully-qualified name of the node and the name of the topic
87-
static std::unordered_map<std::string, std::shared_ptr<SubscriberInstance>>&
88-
getRegistry()
73+
static SubscribersRegistry& getRegistry()
8974
{
90-
static std::unordered_map<std::string, std::shared_ptr<SubscriberInstance>>
91-
subscribers_registry;
75+
static SubscribersRegistry subscribers_registry;
9276
return subscribers_registry;
9377
}
9478

@@ -108,7 +92,7 @@ class RosTopicSubNode : public BT::ConditionNode
10892
/** You are not supposed to instantiate this class directly, the factory will do it.
10993
* To register this class into the factory, use:
11094
*
111-
* RegisterRosAction<DerivedClasss>(factory, params)
95+
* RegisterRosAction<DerivedClass>(factory, params)
11296
*
11397
* Note that if the external_action_client is not set, the constructor will build its own.
11498
* */
@@ -118,22 +102,6 @@ class RosTopicSubNode : public BT::ConditionNode
118102
virtual ~RosTopicSubNode()
119103
{
120104
signal_connection_.disconnect();
121-
// remove the subscribers from the static registry when the ALL the
122-
// instances of RosTopicSubNode are destroyed (i.e., the tree is destroyed)
123-
if(sub_instance_)
124-
{
125-
sub_instance_.reset();
126-
std::unique_lock lk(registryMutex());
127-
auto& registry = getRegistry();
128-
auto it = registry.find(subscriber_key_);
129-
// when the reference count is 1, means that the only instance is owned by the
130-
// registry itself. Delete it
131-
if(it != registry.end() && it->second.use_count() <= 1)
132-
{
133-
registry.erase(it);
134-
RCLCPP_INFO(logger(), "Remove subscriber [%s]", topic_name_.c_str());
135-
}
136-
}
137105
}
138106

139107
/**
@@ -190,6 +158,26 @@ class RosTopicSubNode : public BT::ConditionNode
190158
//----------------------------------------------------------------
191159
//---------------------- DEFINITIONS -----------------------------
192160
//----------------------------------------------------------------
161+
template <class T>
162+
inline RosTopicSubNode<T>::SubscriberInstance::SubscriberInstance(
163+
std::shared_ptr<rclcpp::Node> node, const std::string& topic_name)
164+
{
165+
// create a callback group for this particular instance
166+
callback_group =
167+
node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive, false);
168+
callback_group_executor.add_callback_group(callback_group,
169+
node->get_node_base_interface());
170+
171+
rclcpp::SubscriptionOptions option;
172+
option.callback_group = callback_group;
173+
174+
// The callback will broadcast to all the instances of RosTopicSubNode<T>
175+
auto callback = [this](const std::shared_ptr<T> msg) {
176+
last_msg = msg;
177+
broadcaster(msg);
178+
};
179+
subscriber = node->create_subscription<T>(topic_name, 1, callback, option);
180+
}
193181

194182
template <class T>
195183
inline RosTopicSubNode<T>::RosTopicSubNode(const std::string& instance_name,
@@ -262,17 +250,15 @@ inline bool RosTopicSubNode<T>::createSubscriber(const std::string& topic_name)
262250
auto it = registry.find(subscriber_key_);
263251
if(it == registry.end())
264252
{
265-
it = registry.insert({ subscriber_key_, std::make_shared<SubscriberInstance>() })
266-
.first;
267-
sub_instance_ = it->second;
268-
sub_instance_->init(node_, topic_name);
253+
sub_instance_ = std::make_shared<SubscriberInstance>(node_, topic_name);
254+
registry.insert({ subscriber_key_, sub_instance_ });
269255

270256
RCLCPP_INFO(logger(), "Node [%s] created Subscriber to topic [%s]", name().c_str(),
271257
topic_name.c_str());
272258
}
273259
else
274260
{
275-
sub_instance_ = it->second;
261+
sub_instance_ = it->second.lock();
276262
}
277263

278264
// Check if there was a message received before the creation of this subscriber action

0 commit comments

Comments
 (0)