Synchronizing STD cout output multi-thread
Asked Answered
A

5

10

Latelly I've been working with multi-thread coding, after a while writing I realized that if I used std::cout in different boost::threads, the output would came without a logical order, the program that I'm testing is something like:

#include <boost/thread/thread.hpp>
#include <iostream>

int my01( void )
{
    std::cout << "my01" << std::endl;
    return 0;
}
/* my02, my03 and my04 are the same with different outputs*/
[...]
int main( void )
{
    boost::thread t1(&my01);
    boost::thread t2(&my02);
    boost::thread t3(&my03);
    boost::thread t4(&my04);

    while(!t1.joinable() || !t2.joinable() || !t3.joinable() || !t4.joinable());

    t1.join();
    t2.join();
    t3.join();
    t4.join();

    std::cout << "The end!" << std::endl;
    getchar();
    return 0;
}


And the output is usually like (it changes):

my02my01
my04
my03
BLANK LINE
The end!

With this issue in mind I was thinking of creating a single thread to manage all of the outputs, so they would be in order like:

my01
my02
my03
my04
The end!

Which is the optimal way to write such thread or to manage those outputs?
Please read the answers to this question too: Is cout synchronized/thread-safe?

Ps:I'm using Visual C++ 2010 Express and my cpu has 8 different cores.

Thank you for your time!

Arequipa answered 17/2, 2012 at 16:51 Comment(1)
I have exactly the same problem but i have no control over the code that uses boost::threads, so for me the solution posted below is not an option. How to manage output synchronicity without rewriting the use of boost::thread's?Agata
I
10

First of all, you might consider avoiding all the explicit thread management, and instead use std::async to launch your tasks in some arbitrary number of separate threads.

Second, instead of doing the I/O in the threads themselves, you want to create results, and do the output itself serially. This means the thread function just creates some data, and leaves it to the caller to actually write that out:

std::string process(int value) {
     std::ostringstream buffer;
     buffer << "my" << std::setfill('0') << std::setw(2) << value;
     return buffer.str();
}

Then we need to launch four copies of that asychronously:

std::vector<std::future<std::string> > results;

for (int i=0; i<4; i++)
    results.push_back(std::async(std::launch::async, process, i));

Then we get the results and print them out in order:

for (auto &r : results)
    std::cout << r.get() << "\n";

Putting those together, we could get code like this:

#include <string>
#include <iostream>
#include <thread>
#include <future>
#include <sstream>
#include <vector>
#include <iomanip>

std::string process(int value) {
     std::ostringstream buffer;
     buffer << "my" << std::setfill('0') << std::setw(2) << value;
     return buffer.str();
}

int main() { 
    std::vector<std::future<std::string>> rets;

    for (int i=0; i<4; i++)
        rets.push_back(std::async(std::launch::async, process, i));

    for (auto & t : rets) {
        t.wait();
        std::cout << t.get() << "\n";
    }
}

I should add one minor point: I'm basing this on standard C++11 futures. I believe the basic idea should also work with Boost futures (upon which the standard was based) but I haven't tested that. I'd expect that some minor adjustments (e.g., to names) will be needed to work with Boost's futures.

Interior answered 17/2, 2012 at 18:1 Comment(0)
T
5

I resolved it by coding up a thin wrapper that locks a mutex on starting writing to the stream and releases it, along with flushing the stream, once the write statement is completed.

Usage: replace std::cout by safe_cout.

Keep in mind it does not support fancy std::cout features like std::endl.

See the code below or grab it from here: https://github.com/dkorolev/felicity/blob/master/safe_ostream.h

#include <cassert>
#include <iostream>
#include <mutex>
#include <memory>

struct safe_ostream {
  struct guarded_impl {
    guarded_impl() = delete;
    guarded_impl(const guarded_impl&) = delete;
    void operator=(const guarded_impl&) = delete;
    guarded_impl(std::ostream& ostream, std::mutex& mutex) : ostream_(ostream), guard_(mutex) {
    }
    ~guarded_impl() {
      ostream_.flush();
    }
    template<typename T> void write(const T& x) {
      ostream_ << x;
    }
    std::ostream& ostream_;
    std::lock_guard<std::mutex> guard_;
  };
  struct impl {
    impl() = delete;
    void operator=(const impl&) = delete;
    impl(std::ostream& ostream, std::mutex& mutex) : unique_impl_(new guarded_impl(ostream, mutex)) {
    }
    impl(const impl& rhs) {
      assert(rhs.unique_impl_.get());
      unique_impl_.swap(rhs.unique_impl_);
    }
    template<typename T> impl& operator<<(const T& x) {
      guarded_impl* p = unique_impl_.get();
      assert(p);
      p->write(x);
      return *this;
    }
    mutable std::unique_ptr<guarded_impl> unique_impl_;
  };
  explicit safe_ostream(std::ostream& ostream) : ostream_(ostream) {
  }
  template<typename T> impl operator<<(const T& x) {
    return impl(ostream_, mutex_) << x;
  }
  std::ostream& ostream_;
  std::mutex mutex_;
};
safe_ostream safe_cout(std::cout);
safe_ostream safe_cerr(std::cerr);
Tenderfoot answered 23/1, 2014 at 5:3 Comment(1)
Dima, locking is evil.Nagoya
F
2

You either need to impose an order on the threads so that the ordering of the output is as you want, (perhaps by passing thread-instances or events to the appropriate threads so that they can only execute in your order), or you could give all the outputs a thread-sequence number, queue all the outputs to one 'print' thread and, in there, keep a list of any out-of-order lines so that the printout is as you want.

In the case of a 'real' app, (ie. not a trivial test app that misuses threads), where the threads do a lot of work in parallel on sequential buffers whose order must be preserved, forcing threads to wait for each other is not usually a reasonable option. It's usual to use sequence numbers and reassemble the buffer-stream afterwards.

Fascia answered 17/2, 2012 at 17:13 Comment(0)
A
1

Give each thread a std::ostringstream to write output to. At the end of the program, print each thread's output in order.

How else would you do it, considering that thread 4 may finish long before thread 1?

Attain answered 17/2, 2012 at 17:16 Comment(2)
The program will be running for a long period of time, so I tought of writing a thread that manages a thread-safe buffer that outputs everything.Arequipa
your requirements ('in order') look like that the entire output of thread 1 must be printed before the output of thread 2 is printed. You might as well just print to cout from thread 1 and use an std::ostringstream in all other threads as Zan proposes.Combine
C
0

Use locking. If you can use boost, do e.g.

int my01(boost::mutex *coutGuard)
{
  {
     // lock cout until the closing brace
     boost::mutex::scoped_lock lock(*coutGuard);

     std::cout << "my01" << std::endl;
  }

  return 0;
}

int main( void )
{
   boost::mutex coutGuard;

   boost::thread t1(boost::bind(&my01, &coutGuard));
   ...
}

Instead of a scoped_lock, lock_guard may be used.

Combine answered 19/12, 2012 at 12:57 Comment(1)
I think it's almost there but with this mutex schema you don't have a way to guarantee the order, something else must be used.Seagoing

© 2022 - 2024 — McMap. All rights reserved.