From f08d42fcb84a3969a47ef4b0714177ac9245c4ce Mon Sep 17 00:00:00 2001 From: Dennis Klein Date: Wed, 10 Jun 2026 16:12:35 +0200 Subject: [PATCH] fix: serialize console output in fair::mq::tools::execute - concurrent execute() calls print captured subprocess lines to std::cout from multiple threads; the standard allows that, but libstdc++ maintains the formatted-output state (ios_base::width) with plain reads and writes -- a data race ThreadSanitizer reports once libstdc++ itself is instrumented - a mutex around the insertion also keeps whole lines from interleaving --- fairmq/tools/Process.cxx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/fairmq/tools/Process.cxx b/fairmq/tools/Process.cxx index 046d1dae..05be0aae 100644 --- a/fairmq/tools/Process.cxx +++ b/fairmq/tools/Process.cxx @@ -18,6 +18,7 @@ #include #include // kill, signals #include +#include #include #include #include @@ -40,10 +41,18 @@ class LinePrinter , fPrefix(std::move(prefix)) {} - // prints line with prefix on both cout (thread-safe) and output stream + // prints line with prefix on both cout and output stream void Print(const string& line) { - cout << fair::mq::tools::ToString(fPrefix, line, "\n") << flush; + // Serialize: the standard allows concurrent insertion on std::cout, + // but libstdc++ maintains the formatted-output state (e.g. + // ios_base::width) with plain reads and writes that constitute data + // races; the lock also keeps whole lines from interleaving. + static mutex sCoutMutex; + { + lock_guard lock(sCoutMutex); + cout << fair::mq::tools::ToString(fPrefix, line, "\n") << flush; + } fOut << fPrefix << line << endl; }