2

I want to ask exactly the same question as was asked here: Synchronizing STD cout output multi-thread with the single exception that i DO NOT have control over the code in which boost::thread s are used (that code is internal to this library, and I should not / want not to touch it, unless this problem can not be solved in any other way, in which case I could add it to my fork of the library.)

The library at a certain time spawns 4 threads (I'm on a mid-2010 MacBook Pro using OSX 10.10) in the C++ code that is executed in a single thread I use cout for logging, like so:

cout << "Writing file: " << "\n" << xmlFileName << endl;

This output gets garbled due to multi-threading so it gets hard to understand what is going on in a single thread at any given moment...

How can I get the output synchronized ? The project uses Boost 1.57.0 so I can use that. I have never had to deal with multi-threading before but I understand the concepts and problems that arise. I have also seen some examples on SO but all of them require access to the code that spawns threads, either using a shared Mutex passed to the threads or using a lockGuard.

Although I have the feeling I can not escape modifying the library code, I hope that this is somehow possible?

Community
  • 1
  • 1
Michahell
  • 4,905
  • 5
  • 29
  • 45
  • _"How can I get the output synchronized ?"_ Not without a `std::mutex` or another synchronization mechanism interacting with the other threads, ensuring that `cout << "Writing file: " << "\n" << xmlFileName << endl;` is performed _atomically_ AFAIK. – πάντα ῥεῖ Feb 02 '15 at 18:35
  • Why do you write to stdout? You could use a proper logging library that has an idea of what consists a complete log message and works multithreaded. It should also allow e.g. adding a thread ID to every log entry, making it easier to figure out which part belongs to which thread. – Ulrich Eckhardt Feb 02 '15 at 22:22
  • I am inheriting a 5 year old legacy project. Actually, the writers thought of including the thread ID and information like so: ```#define screen cout << fixed << "["<< thread_id <<"]: " << name <<" [" < – Michahell Feb 03 '15 at 01:18

1 Answers1

0
  1. You could get extremely hacky and write a sycnhronizing stream buffer.

    You could then use that on the cout object:

    std::cout.rdbuf(new my_sync_cout_buf());
    

    before you start the threads.

    Note that this will require some amount of fidgeting to respond to flushes in a nice fashion. Doing this will break down if (one of the) threads uses std::unitbuf or std::flush liberally.

    In the absolute worst case you'd have to switch on thread id and interlace the output (e.g. line-by-line)

    THINKO: the ostream object itself would still be non-threadsafe. So it's just option #2 then, really:

  2. Perhaps it's easier (and saner) to just open pipes from one thread and read them from another. This way you can coordinate the order in which output is done yourself. Of course, since you don't control the threads, you'd have to fork instead of starting threads.

    Then, in each child process, you can setup the stream buffer of std::cout to write to the pipe

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Actually I used the first approach and it worked for me - not perfectly, but sufficiently. The reason is that IOStreams are to a large extent stateless, in particular there are no buffers that require thread-safe allocation, those are in the streambuffer. Now, what you shouldn't do is to use e.g. format-changing inserters like `std::hex`, because those are sticky and operate across threads. – Ulrich Eckhardt Feb 02 '15 at 22:28
  • @UlrichEckhardt I realized this loophole. But I'd never recommend it. I prefer to give the /straight up/ answer, But I realize that if you can /prove/ that your using the `iostream` instance "as-if" `const`, you could get away with it (which is exactly the line of of thinking that produced option 1. in the first place). I hope you will do wisely and have success :) – sehe Feb 02 '15 at 22:38