I have a multi-threaded application, which heavily uses std::cout
for logging without any locking. In such a case, how can I easily add lock mechanism to make std::cout
thread-safe?
I don't want to search for each occurrence of std::cout
and add a line of locking code. That is too tedious.
Any better practice?
Note: This answer is pre-C++20 so it does not use std::osyncstream
with its separate buffering, but uses a lock instead.
I guess you could implement your own class which wraps cout
and associates a mutex with it. The operator <<
of that new class would do three things:
<<
for the wrapped stream and the passed argumentThis different class would keep the lock and delegate operator <<
to the wrapped stream. The destructor of that second class would eventually destroy the lock and release the mutex.
So any output you write as a single statement, i.e. as a single sequence of <<
invocations, will be printed atomically as long as all your output goes through that object with the same mutex.
Let's call the two classes synchronized_ostream
and locked_ostream
. If sync_cout
is an instance of synchronized_ostream
which wraps std::cout
, then the sequence
sync_cout << "Hello, " << name << "!" << std::endl;
would result in the following actions:
synchronized_ostream::operator<<
would aquire the locksynchronized_ostream::operator<<
would delegate the printing of "Hello, " to cout
operator<<(std::ostream&, const char*)
would print "Hello, "synchronized_ostream::operator<<
would construct a locked_ostream
and pass the lock to thatlocked_ostream::operator<<
would delegate the printing of name
to cout
operator<<(std::ostream&, std::string)
would print the namecout
happens for the exclamation point and the endline manipulatorlocked_ostream
temporary gets destructed, the lock is released