Skip to content

Commit 06a1f4c

Browse files
committed
fix thread safety
1 parent 617743b commit 06a1f4c

File tree

8 files changed

+171
-6
lines changed

8 files changed

+171
-6
lines changed

docs/images/SequenceStar.svg

Lines changed: 1 addition & 1 deletion
Loading

include/behaviortree_cpp_v3/action_node.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <atomic>
1818
#include <thread>
1919
#include <future>
20+
#include <mutex>
21+
2022
#include "leaf_node.h"
2123

2224
namespace BT
@@ -135,6 +137,7 @@ class AsyncActionNode : public ActionNodeBase
135137
std::exception_ptr exptr_;
136138
std::atomic_bool halt_requested_;
137139
std::future<NodeStatus> thread_handle_;
140+
std::mutex m_;
138141
};
139142

140143
/**

include/behaviortree_cpp_v3/blackboard.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class Blackboard
117117
void set(const std::string& key, const T& value)
118118
{
119119
std::unique_lock<std::mutex> lock(mutex_);
120+
std::unique_lock<std::mutex> lock_entry(entry_mutex_);
120121
auto it = storage_.find(key);
121122

122123
if( auto parent = parent_bb_.lock())
@@ -130,10 +131,10 @@ class Blackboard
130131
auto parent_info = parent->portInfo(remapped_key);
131132
if( parent_info )
132133
{
133-
storage_.insert( {key, Entry( *parent_info ) } );
134+
storage_.emplace( key, Entry( *parent_info ) );
134135
}
135136
else{
136-
storage_.insert( {key, Entry( PortInfo() ) } );
137+
storage_.emplace( key, Entry( PortInfo() ) );
137138
}
138139
}
139140
parent->set( remapped_key, value );
@@ -195,10 +196,18 @@ class Blackboard
195196
storage_.clear();
196197
internal_to_external_.clear();
197198
}
199+
200+
// Lock this mutex before using get() and getAny() and unlock it while you have
201+
// done using the value.
202+
std::mutex& entryMutex()
203+
{
204+
return entry_mutex_;
205+
}
198206

199207
private:
200208

201209
struct Entry{
210+
202211
Any value;
203212
const PortInfo port_info;
204213

@@ -213,6 +222,7 @@ class Blackboard
213222
};
214223

215224
mutable std::mutex mutex_;
225+
mutable std::mutex entry_mutex_;
216226
std::unordered_map<std::string, Entry> storage_;
217227
std::weak_ptr<Blackboard> parent_bb_;
218228
std::unordered_map<std::string,std::string> internal_to_external_;

include/behaviortree_cpp_v3/tree_node.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ inline Result TreeNode::getInput(const std::string& key, T& destination) const
215215
"but BB is invalid");
216216
}
217217

218+
std::unique_lock<std::mutex> entry_lock( config_.blackboard->entryMutex() );
218219
const Any* val = config_.blackboard->getAny(static_cast<std::string>(remapped_key));
219220
if (val && val->empty() == false)
220221
{

package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
<buildtool_depend condition="$ROS_VERSION == 2">ament_cmake</buildtool_depend>
2020
<depend condition="$ROS_VERSION == 2">rclcpp</depend>
21+
<depend condition="$ROS_VERSION == 2">ament_index_cpp</depend>
2122

2223
<depend>boost</depend>
2324
<depend>libzmq3-dev</depend>

src/action_node.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ void StatefulActionNode::halt()
167167

168168
NodeStatus BT::AsyncActionNode::executeTick()
169169
{
170+
using lock_type = std::unique_lock<std::mutex>;
170171
//send signal to other thread.
171172
// The other thread is in charge for changing the status
172173
if (status() == NodeStatus::IDLE)
@@ -182,16 +183,23 @@ NodeStatus BT::AsyncActionNode::executeTick()
182183
{
183184
std::cerr << "\nUncaught exception from the method tick(): ["
184185
<< registrationName() << "/" << name() << "]\n" << std::endl;
186+
// Set the exception pointer and the status atomically.
187+
lock_type l(m_);
185188
exptr_ = std::current_exception();
186-
thread_handle_.wait();
189+
setStatus(BT::NodeStatus::IDLE);
187190
}
188191
return status();
189192
});
190193
}
191194

195+
lock_type l(m_);
192196
if( exptr_ )
193197
{
194-
std::rethrow_exception(exptr_);
198+
// The official interface of std::exception_ptr does not define any move
199+
// semantics. Thus, we copy and reset exptr_ manually.
200+
const auto exptr_copy = exptr_;
201+
exptr_ = nullptr;
202+
std::rethrow_exception(exptr_copy);
195203
}
196204
return status();
197205
}

src/blackboard.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ void Blackboard::setPortInfo(std::string key, const PortInfo& info)
1818
auto it = storage_.find(key);
1919
if( it == storage_.end() )
2020
{
21-
storage_.insert( { std::move(key), Entry(info) } );
21+
storage_.emplace( key, Entry(info) );
2222
}
2323
else{
2424
auto old_type = it->second.port_info.type();

0 commit comments

Comments
 (0)