57

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?

Parker
  • 7,244
  • 12
  • 70
  • 92
xmllmx
  • 39,765
  • 26
  • 162
  • 323
  • 8
    This was actually one of the topics discussed and given an example for in [this video](http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Herb-Sutter-Concurrency-and-Parallelism). The usage of it comes at about 48 minutes in, and the implementation is a while before that, as there's an example for strings before it. – chris Feb 05 '13 at 22:23
  • 2
    `std::cout` is already thread-safe. Do you mean you want the actual chunks of text to be serialized per flush? – GManNickG Feb 05 '13 at 22:38
  • @GManNickG, really? Which page of the C++ standard provides that? – xmllmx Feb 05 '13 at 22:39
  • [See here, for example](http://stackoverflow.com/a/6374525/87234). – GManNickG Feb 05 '13 at 22:46
  • 8
    Section 27.4.1: `Concurrent access to a synchronized (27.5.3.4) standard iostream object’s formatted and unformatted in- put (27.7.2.1) and output (27.7.3.1) functions or a standard C stream by multiple threads shall not result in a data race (1.10).` – John Schug Feb 05 '13 at 22:48
  • 6
    However, the standard says: "[ Note: Users must still synchronize concurrent use of these objects and streams by multiple threads if they wish to avoid interleaved characters. — end note ]" – xmllmx Feb 05 '13 at 22:49
  • @xmllmx That does not mean that it is thread-unsafe. Have a look at Herb Sutter's video for a really nice solution to this. You could actually post that solution here for completeness. – betabandido Feb 05 '13 at 22:52
  • 5
    @xmllmx: Which goes back to what I said: it's already thread-safe, do you want to further serialize the display of characters per-flush? – GManNickG Feb 05 '13 at 22:55
  • A library: http://neverlord.github.com/libcppa/manual/index_0_5_5.html#sec68 (look for "aout"); http://www.tntnet.org/cxxtools.html has a synchronous logging too, AFAIK. – ArtemGr Feb 05 '13 at 23:09
  • 3
    Yes. I want to output two string "abc" and "123" rather than "a12" and "3bc" – xmllmx Feb 05 '13 at 23:10
  • 1
    Just for the record, I have seen libraries behave erratically when used by multiple threads. The problem was that the hex-flag remained set after some interleaved operations. Real world sometimes doesn't care for The Standard! – Ulrich Eckhardt Feb 06 '13 at 21:22

11 Answers11

57

While I can't be sure this applies to every compiler / version of std libs but in the code-base I'm using std::cout::operator<<() it is already thread-safe.

I'm assuming that what you're really trying to do it stop std::cout from mixing string when concatenating with the operator<< multiple time per string, across multiple threads.

The reason strings get garbled is because there is a "External" race on the operator<< this can lead to things like this happening.

//Thread 1
std::cout << "the quick brown fox " << "jumped over the lazy dog " << std::endl;

//Thread 2
std::cout << "my mother washes" << " seashells by the sea shore" << std::endl;

//Could just as easily print like this or any other crazy order.
my mother washes the quick brown fox seashells by the sea shore \n
jumped over the lazy dog \n

If that's the case there is a much simpler answer than making your own thread safe cout or implementing a lock to use with cout.

Simply compose your string before you pass it to cout

For example.

//There are other ways, but stringstream uses << just like cout.. 
std::stringstream msg;
msg << "Error:" << Err_num << ", " << ErrorString( Err_num ) << "\n"; 
std::cout << msg.str();

This way your stings can't be garbled because they are already fully formed, plus its also a better practice to fully form your strings anyway before dispatching them.

Community
  • 1
  • 1
Nickolas George
  • 579
  • 1
  • 4
  • 3
  • 7
    I think it's important to note that you're referring just to a specific implementation. Which one, and where does it guarantee thread-safety? I haven't looked myself yet, but I doubt that any recent C++ standard guarantees `operator<<(std::ostream&, const std::string&)` to be atomic. If there are no guarantees, then the implementation might still write the string out in chunks on some implementations, interleaving data from different threads. – MvG Mar 10 '16 at 13:11
  • 2
    it's garanteed for std::cout (not std::ofstream in general). – germinolegrand Jul 26 '16 at 01:14
  • 4
    It's worse than that. I'm using Xcode (on OS X) and seeing character-by-character interleaving, making messages nearly unreadable. A mutex-protected wrapper for cout is probably the best way to go. – Jim Carnicelli Aug 19 '16 at 06:27
32

Since C++20, you can use std::osyncstream wrapper:

http://en.cppreference.com/w/cpp/io/basic_osyncstream

{
  std::osyncstream bout(std::cout); // synchronized wrapper for std::cout
  bout << "Hello, ";
  bout << "World!";
  bout << std::endl; // flush is noted, but not yet performed
  bout << "and more!\n";
} // characters are transferred and std::cout is flushed

It provides the guarantee that all output made to the same final destination buffer (std::cout in the examples above) will be free of data races and will not be interleaved or garbled in any way, as long as every write to the that final destination buffer is made through (possibly different) instances of std::basic_osyncstream.

Alternatively, you can use a temporary:

std::osyncstream(std::cout) << "Hello, " << "World!" << '\n';
lilezek
  • 6,976
  • 1
  • 27
  • 45
  • I don't think those options are available to me, I'm using Qt Creator version 4.13.2, based on Qt 5.15.1 Clang 11.0 Apple 64 bit. I don't see the header. – SPlatten Oct 14 '20 at 17:44
  • Do I need to declare `std::osyncstream bout(std::cout)` only once for all cpp files or it is fine to declare it again in each cpp? – gil123 Jan 07 '21 at 16:57
  • As far as I understand (I'm not really confident), ideally, you should have an osyncstream per thread, and they should not be shared between threads. Alternatively, you can use a temporary. I'm going to update my answer with the example from the docs. – lilezek Jan 08 '21 at 17:13
  • 1
    I'm getting fatal error: syncstream: No such file or directory, is there a way to get the header file? – harry Feb 16 '21 at 11:06
  • From the std::cout doc: `Unless sync_with_stdio(false) has been issued, it is safe to concurrently access these objects from multiple threads for both formatted and unformatted output.` - does this mean that the sync stream is not necessary for cout? – csisy Jun 09 '21 at 12:46
  • 2
    @csisy No. That just means that it won't be UB to use `std::cout` from multiple threads. You can still get the "wrong" output. E.g. if thread A does `std::cout << "A: " << 0 << " ";` and thread B does `std::cout << "B: " << 1 << " ";` you can get output like `A: B: 0 1`. That's "safe" but also probably not what you want. But replacing `std::cout` with `std::osyncstream(std::cout)` in both guarantees you get either `A: 0 B: 1` or `B: 1 A: 0`. – HTNW Sep 06 '21 at 17:57
  • 1
    @lilezek You generally do *not* want an `osyncstream` per thread. You want an `osyncstream` *per logical message that should not be interrupted by another thread's text*. – HTNW Sep 06 '21 at 18:00
23

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:

  1. create a lock for the mutex, possibly blocking other threads
  2. do the output, i.e. do the operator << for the wrapped stream and the passed argument
  3. construct an instance of a different class, passing the lock to that

This 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:

  1. synchronized_ostream::operator<< would aquire the lock
  2. synchronized_ostream::operator<< would delegate the printing of "Hello, " to cout
  3. operator<<(std::ostream&, const char*) would print "Hello, "
  4. synchronized_ostream::operator<< would construct a locked_ostream and pass the lock to that
  5. locked_ostream::operator<< would delegate the printing of name to cout
  6. operator<<(std::ostream&, std::string) would print the name
  7. The same delegation to cout happens for the exclamation point and the endline manipulator
  8. The locked_ostream temporary gets destructed, the lock is released
MvG
  • 57,380
  • 22
  • 148
  • 276
  • 2
    This can be simplified a bit. Firstly, if any code doesn't play by the rules, it can still mess with `cout`, which means you must change any occurrence of `cout`. In that case, you can also replace it with `(cout_lock(), cout)`, where `cout_lock()` is a scoped lock type specifically for syncing access to `cout`. This will create a temporary object living until the next line, while the result of the expression `(A, B)` is `B` due to the comma operator. I'd claim that this is less code, and you still can lock the mutex for more than a line, if you want. – Ulrich Eckhardt Feb 06 '13 at 21:51
  • 1
    @doomster: explicitely maintaining a `locked_ostream` for more than a single expression would be possible with my setup as well, but your aproach is interesting as well. It does appear to be asking for a macro, though, which is a rather un-C++-ish way to deal with issues. Otherwise, always coding the lock will become tedious. – MvG Feb 06 '13 at 21:58
  • 2
    @MvG: He's not using a macro, he's using the comma operator. Regardless, this can be simplified. Replace `cout` with an object that buffers until it receives a `'\n'`, and then locks, dumps the entire buffer to `cout`, and unlocks, all at once. – Mooing Duck Jul 13 '17 at 01:01
  • 1
    @MooingDuck: I was mentioning macro because the same pattern (the one with the comma in it) would be repeated all over the place. The buffer then flush whole lines approach makes sense if single line atomicity is all you need, but e.g. a multi-line stack trace interleaved with other stuff can be quite confusing, so that's not always the best approach. – MvG Jul 13 '17 at 02:14
  • 1
    @MvG As you know, C++20 brings `osyncstream` which is similar to your `synchronized_ostream` wrapper. Would you mind updating your answer to reflect that? – L. F. Mar 25 '19 at 12:58
  • 1
    @L.F. I hadn't known about that, thanks for the comment. The way I read [cppreference](https://en.cppreference.com/w/cpp/io/basic_osyncstream), `std::osyncstream` is more like my `locked_ostream` in that it should be scoped to one atomic write operation. And the internal implementation appears different, too, since that one buffers independently so things writing to log could still execute concurrently, which they cannot in my suggestion here. That comes at a cost for copying output around. On the whole I believe `osyncstream` is better off in a separate answer, but I'll reference that. – MvG Mar 25 '19 at 13:22
  • @MvG Thank you! Honestly, I am myself quite confused about all these lock things ;-) And you cleared it up for me! – L. F. Mar 25 '19 at 13:24
  • 1
    @LF: [`std::osyncstream`](http://en.cppreference.com/w/cpp/io/basic_osyncstream) is included with but still not yet available for C++20. You can verify this by checking compiler support for `synchronized buffered ostream` [here](https://en.cppreference.com/w/cpp/compiler_support). Until it is available (or you use an unofficial implementation), you are probably going to have to use a lock. – Fake Code Monkey Rashid Sep 02 '20 at 18:19
18

I really like the trick from Nicolás given in this question of creating a temporary object and putting the protection code on the destructor.

/** Thread safe cout class
  * Exemple of use:
  *    PrintThread{} << "Hello world!" << std::endl;
  */
class PrintThread: public std::ostringstream
{
public:
    PrintThread() = default;

    ~PrintThread()
    {
        std::lock_guard<std::mutex> guard(_mutexPrint);
        std::cout << this->str();
    }

private:
    static std::mutex _mutexPrint;
};

std::mutex PrintThread::_mutexPrint{};

You can then use it as a regular std::cout, from any thread:

PrintThread{} << "my_val=" << val << std::endl;

The object collect data as a regular ostringstream. As soon the coma is reached, the object is destroyed and flush all collected information.

Community
  • 1
  • 1
Conchylicultor
  • 4,631
  • 2
  • 37
  • 40
  • I wonder if you could do `class PrintThreadType {}; PrintThreadType& getPrintThread() {static PrintThreadType a; return a;} PrintThreadType& PrintThread = getPrintThread();` in a header to sidestep odr? Probably doesn't work. – Mooing Duck Jul 13 '17 at 01:06
  • 3
    You gotta be careful with this idea. Destructors in C++ should not be allowed to throw exceptions. By default, in C++11 (and, I presume, beyond), if an exception propagates out of a destructor, it will call std::terminate. – Kef Schecter Nov 06 '17 at 00:30
  • What does this last line do? `std::mutex PrintThread::_mutexPrint{};` – Ari May 28 '20 at 16:59
  • @Ari, `_mutexPrint` is a static variable (common to all instance of `PrintThread`) (See: https://en.cppreference.com/w/cpp/language/static), the `{}` is just one of the many syntax to initialise an object (since C++11) (See: https://en.cppreference.com/w/cpp/language/value_initialization). So the last line initialise the static variable once. – Conchylicultor May 28 '20 at 21:51
  • 2
    @KefSchecter, if this is really an issue in practice, I guess one could try to wrap the destructor code in some `try {} catch(...) {}` to silent the error instead of terminating. But this is indeed a limitation of this method. – Conchylicultor Aug 06 '20 at 08:41
8

Along the lines of the answer suggested by Conchylicultor, but without inheriting from std::ostringstream:


EDIT: Fixed return type for the overloaded operator and added overload for std::endl.


EDIT 1: I have extended this into a simple header-only library for logging / debugging multi-threaded programs.


#include <iostream>
#include <mutex>
#include <thread>
#include <vector>    
#include <chrono>

static std::mutex mtx_cout;

// Asynchronous output
struct acout
{
        std::unique_lock<std::mutex> lk;
        acout()
            :
              lk(std::unique_lock<std::mutex>(mtx_cout))
        {

        }

        template<typename T>
        acout& operator<<(const T& _t)
        {
            std::cout << _t;
            return *this;
        }

        acout& operator<<(std::ostream& (*fp)(std::ostream&))
        {
            std::cout << fp;
            return *this;
        }
};

int main(void)
{


    std::vector<std::thread> workers_cout;
    std::vector<std::thread> workers_acout;

    size_t worker(0);
    size_t threads(5);


    std::cout << "With std::cout:" << std::endl;

    for (size_t i = 0; i < threads; ++i)
    {
        workers_cout.emplace_back([&]
        {
            std::cout << "\tThis is worker " << ++worker << " in thread "
                      << std::this_thread::get_id() << std::endl;
        });
    }
    for (auto& w : workers_cout)
    {
        w.join();
    }

    worker = 0;

    std::this_thread::sleep_for(std::chrono::seconds(2));

    std::cout << "\nWith acout():" << std::endl;

    for (size_t i = 0; i < threads; ++i)
    {
        workers_acout.emplace_back([&]
        {
            acout() << "\tThis is worker " << ++worker << " in thread "
                    << std::this_thread::get_id() << std::endl;
        });
    }
    for (auto& w : workers_acout)
    {
        w.join();
    }

    return 0;
}

Output:

With std::cout:
        This is worker 1 in thread 139911511856896
        This is worker  This is worker 3 in thread 139911495071488
        This is worker 4 in thread 139911486678784
2 in thread     This is worker 5 in thread 139911503464192139911478286080


With acout():
        This is worker 1 in thread 139911478286080
        This is worker 2 in thread 139911486678784
        This is worker 3 in thread 139911495071488
        This is worker 4 in thread 139911503464192
        This is worker 5 in thread 139911511856896
cantordust
  • 1,542
  • 13
  • 17
6

For fast debugging c++11 applications and avoid interleaved output I just write small functions like these:

...
#include <mutex>
...
mutex m_screen;
...
void msg(char const * const message);
...
void msg(char const * const message)
{
  m_screen.lock();
  cout << message << endl;
  m_screen.unlock();
}

I use these types of functions for outputs and if numeric values are needed I just use something like this:

void msgInt(char const * const message, int const &value);
...
void msgInt(char const * const message, int const &value)
{
  m_screen.lock();
  cout << message << " = " << value << endl;
  m_screen.unlock();
}

This is easy and works fine to me, but I don't really know if it is technically correct. So I would be glad to hear your opinions.


Well, I didn't read this:

I don't want to search for each occurrence of std::cout and add a line of locking code.

I'm sorry. However I hope it helps somebody.

Germinx
  • 61
  • 1
  • 3
  • 8
    This code isn't safe, because cout can throw an exception and then your mutex never gets unlocked. You should use std::lock_guard with the mutex to ensure the mutex will get released no matter what when you're done with it. – Kef Schecter Nov 06 '17 at 05:26
5

A feasible solution uses a line-buffer for each thread. You might get interleaved lines, but not interleaved characters. If you attach that to thread-local storage, you also avoid lock contention issues. Then, when a line is full (or on flush, if you want), you write it to stdout. This last operation of course has to use a lock. You stuff all this into a streambuffer, which you put between std::cout and its original streambuffer (a.k.a. Decorator Pattern).

The problem this doesn't solve is things like format flags (e.g. hex/dec/oct for numbers), which can sometimes percolate between threads, because they are attached to the stream. It's nothing bad, assuming you're only logging and not using it for important data. It helps to just not format things specially. If you need hex output for certain numbers, try this:

template<typename integer_type>
std::string hex(integer_type v)
{
    /* Notes:
    1. using showbase would still not show the 0x for a zero
    2. using (v + 0) converts an unsigned char to a type
       that is recognized as integer instead of as character */
    std::stringstream s;
    s << "0x" << std::setfill('0') << std::hex
        << std::setw(2 * sizeof v) << (v + 0);
    return s.str();
}

Similar approaches work for other formats as well.

Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55
  • Aren't the contents of lines written to a common buffer first? If so, the line-buffered print is not thread-safe at all! – duleshi Oct 26 '15 at 06:52
  • I'm not sure what you mean, as I said on the first level, each thread has its own buffer, so there's no common buffer. On the second level, there is indeed a common buffer, but that buffer "has to use a lock" as I wrote above. Both is thread-safe to me. – Ulrich Eckhardt Oct 26 '15 at 06:56
  • Sorry for not reading through. My habit is to read the first few sentences and look at the code samples, and I didn't find any locks there. I tend to treat the beginning or ending as a summary. And I think answers fit for a quick glance is really great. – duleshi Oct 26 '15 at 07:13
  • @UlrichEckhardt Is `template ` what you mean? The code is valid as is, but it doesn't make much sense ;) – L. F. Feb 11 '19 at 09:58
1

I know its an old question, but it helped me a lot with my problem. I created an utility class based on this post answers and I'd like to share my result.

Considering we use C++11 or latter C++ versions, this class provides print and println functions to compose strings before calling the standard output stream and avoid concurrency problems. These are variadic functions which use templates to print different data types.

You can check its use in a producer-consumer problem on my github: https://github.com/eloiluiz/threadsBar

So, here is my code:

class Console {
private:
    Console() = default;

    inline static void innerPrint(std::ostream &stream) {}

    template<typename Head, typename... Tail>
    inline static void innerPrint(std::ostream &stream, Head const head, Tail const ...tail) {
        stream << head;
        innerPrint(stream, tail...);
    }

public:
    template<typename Head, typename... Tail>
    inline static void print(Head const head, Tail const ...tail) {
        // Create a stream buffer
        std::stringbuf buffer;
        std::ostream stream(&buffer);
        // Feed input parameters to the stream object
        innerPrint(stream, head, tail...);
        // Print into console and flush
        std::cout << buffer.str();
    }

    template<typename Head, typename... Tail>
    inline static void println(Head const head, Tail const ...tail) {
        print(head, tail..., "\n");
    }
};
eloiluiz
  • 21
  • 5
0

This is how I manage thread safe operations on std::cout using a custom enum and macros:

enum SynchronisedOutput { IO_Lock, IO_Unlock };

inline std::ostream & operator<<(std::ostream & os, SynchronisedOutput so) {
  static std::mutex mutex;

  if (IO_Lock == so) mutex.lock();
  else if (IO_Unlock == so)
    mutex.unlock();

  return os;
}

#define sync_os(Os) (Os) << IO_Lock
#define sync_cout sync_os(std::cout)
#define sync_endl '\n' << IO_Unlock

This allow me to write things like:

sync_cout << "Hello, " << name << '!' << sync_endl;

in threads without racing issues.

0

I had a similar problem to yours. You can use the following class. This only supports outputting to std::cout, but if you need a general one let me know. In the code below, tsprint creates an inline temporary object of the class ThreadSafePrinter. If you want, you can change tsprint to cout if you have used cout instead of std::cout, so you won't have to replace any instances of cout but I do not recommend such a practice in general. It is much better to use a special output symbol for such debug lines starting from the beginning of the project anyway.

I like this solution as well: 1. In my solution all threads can continue inserting into their corresponding thread_local stringstream static-objects and then lock the mutex only when it is required to flush which is triggered in the destructor. This is expected to improve the efficiency by shortening the duration during which the mutex-lock is held. Maybe I can include a mechanism similar to the sync_endl solution mentioned in 1.

class ThreadSafePrinter
{
    static mutex m;
    static thread_local stringstream ss;
public:
    ThreadSafePrinter() = default;
    ~ThreadSafePrinter()
    {
        lock_guard  lg(m);
        std::cout << ss.str();
        ss.clear();
    }

    template<typename T>
    ThreadSafePrinter& operator << (const T& c)
    {
        ss << c;
        return *this;
    }


    // this is the type of std::cout
    typedef std::basic_ostream<char, std::char_traits<char> > CoutType;

    // this is the function signature of std::endl
    typedef CoutType& (*StandardEndLine)(CoutType&);

    // define an operator<< to take in std::endl
    ThreadSafePrinter& operator<<(StandardEndLine manip)
    {
        manip(ss);
        return *this;
    }
};
mutex ThreadSafePrinter::m;
thread_local stringstream ThreadSafePrinter::ss;
#define tsprint ThreadSafePrinter()

void main()
{
    tsprint << "asd ";
    tsprint << "dfg";
}
Eddie
  • 36
  • 3
  • While the answer offers a workaround it is technically not a solution to the question. Considering the purpose of the proposed method, it should be clarified that the static and thread_local members must not be instantiated in the header file that defines the proposed class. (See https://stackoverflow.com/a/18861043/3434933) – Pierre Schroeder Nov 08 '21 at 14:29
  • @PierreSchroeder Thank you for the feedback! Regarding your first point: yes this is a workaround like others' solutions on this page. To address the second part, I just copy-pasted the code from my main file (note that just below the class there is a main call), so it works in a single file. I assume anyone asking this type of advanced question would be able to know that they should not place the static object definitions inside header files. Of course, t does not mean that my assumption holds in general. Another point: my solutions keeps the lock shorter using the thread-local stringstream. – Eddie Nov 09 '21 at 08:24
-1

In addition to synchronisation this solution provides information about the thread from which the log was written.

DISCLAIMER: It's quite a naive way of syncing the logs, however it might be applicable for some small use cases for debugging.

thread_local int thread_id = -1;
std::atomic<int> thread_count;

struct CurrentThread {

  static void init() {
    if (thread_id == -1) {
      thread_id = thread_count++;
    }
  }

  friend std::ostream &operator<<(std::ostream &os, const CurrentThread &t) {
    os << "[Thread-" << thread_id << "] - ";
    return os;
  }
};

CurrentThread current_thread;
std::mutex io_lock;
#ifdef DEBUG
#define LOG(x) {CurrentThread::init(); std::unique_lock<std::mutex> lk(io_lock); cout << current_thread << x << endl;}
#else
#define LOG(x)
#endif

This can be used like this.

LOG(cout << "Waiting for some event");

And it will give log output

[Thread-1] - Entering critical section 
[Thread-2] - Waiting on mutex
[Thread-1] - Leaving critical section, unlocking the mutex
samvel1024
  • 1,123
  • 4
  • 15
  • 39