Skip to content

Commit 8a47045

Browse files
facontidavideclaude
andcommitted
fix(loggers): add explicit sync between writer thread and callbacks
Add writer_ready atomic flag to ensure the writer thread is fully initialized before callbacks can fire. This provides a clear happens-before relationship that TSAN can verify. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent ee6d881 commit 8a47045

3 files changed

Lines changed: 20 additions & 0 deletions

File tree

include/behaviortree_cpp/loggers/bt_sqlite_logger.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ class SqliteLogger : public StatusChangeLogger
100100

101101
std::thread writer_thread_;
102102
std::atomic_bool loop_ = true;
103+
std::atomic_bool writer_ready_ = false;
103104

104105
ExtraCallback extra_func_;
105106

src/loggers/bt_file_logger_v2.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ struct FileLogger2::Pimpl
3737

3838
std::thread writer_thread;
3939
std::atomic_bool loop = true;
40+
std::atomic_bool writer_ready = false; // Signals writer thread is in wait loop
4041
};
4142

4243
FileLogger2::FileLogger2(const BT::Tree& tree, std::filesystem::path const& filepath)
@@ -82,6 +83,12 @@ FileLogger2::FileLogger2(const BT::Tree& tree, std::filesystem::path const& file
8283
_p->file_stream.write(write_buffer.data(), 8);
8384

8485
_p->writer_thread = std::thread(&FileLogger2::writerLoop, this);
86+
87+
// Wait for writer thread to be ready before subscribing to callbacks
88+
while(!_p->writer_ready.load(std::memory_order_acquire))
89+
{
90+
std::this_thread::yield();
91+
}
8592
subscribeToTreeChanges(tree.rootNode());
8693
}
8794

@@ -118,6 +125,9 @@ void FileLogger2::writerLoop()
118125
// local buffer in this thread
119126
std::deque<Transition> transitions;
120127

128+
// Signal that writer is ready to receive callbacks
129+
_p->writer_ready.store(true, std::memory_order_release);
130+
121131
while(_p->loop)
122132
{
123133
transitions.clear();

src/loggers/bt_sqlite_logger.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ SqliteLogger::SqliteLogger(const Tree& tree, std::filesystem::path const& filepa
129129
}
130130

131131
writer_thread_ = std::thread(&SqliteLogger::writerLoop, this);
132+
133+
// Wait for writer thread to be ready before subscribing to callbacks
134+
while(!writer_ready_.load(std::memory_order_acquire))
135+
{
136+
std::this_thread::yield();
137+
}
132138
subscribeToTreeChanges(tree.rootNode());
133139
}
134140

@@ -205,6 +211,9 @@ void SqliteLogger::writerLoop()
205211
{
206212
std::deque<Transition> transitions;
207213

214+
// Signal that writer is ready to receive callbacks
215+
writer_ready_.store(true, std::memory_order_release);
216+
208217
while(loop_)
209218
{
210219
transitions.clear();

0 commit comments

Comments
 (0)