Synchronizing STD cout output with multiple threads

Latelly I work with multi-threaded coding, after a while I realized that if I used std :: cout in different boost :: threads, the output would be executed without a logical order, the program, m 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 similar (it changes):

my02my01
my04
my03
FORM LINE
The end!

Given this problem, I was thinking of creating a single thread to control all the outputs, so they would be in order, like:

my01
my02
my03
my04
The end!

What is the best way to record such a stream or control these pins?
Please also read the answers to this question: Is cout synchronized / thread safe?

Ps: I am using Visual C ++ 2010 Express, and my processor has 8 different cores.

Thank you for your time!

+5
source share
5 answers

First of all, you can consider avoiding all the explicit flow control and instead use std::async to run your tasks in an arbitrary number of separate threads.

Secondly, instead of I / O in the threads themselves, you want to create results and perform the output yourself. This means that the stream function simply creates some data and leaves it to the caller to actually write this:

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

Then we need to run four copies of this asynchronously:

 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 in order:

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

Putting them 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 have to add one minor point: I base this on future C ++ 11 standards. I believe that the main idea should also work with future Boost (on which the standard was based), but I have not tested this. I expect that some minor changes (for example, to names) will be needed to work with Boost futures.

+8
source

I resolved it by encoding a thin shell that blocks the mutex when it starts recording to the stream and frees it, and also cleans the stream after the recording is complete.

Usage: replace std :: cout with safe_cout.

Keep in mind that it does not support the trendy functions of std :: cout, such as std :: endl.

See the code below or grab it 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); 
+4
source

You either need to put the order on the streams so that the output order is what you want (perhaps by passing event streams or events to the corresponding streams so that they can be executed only in your order) or you can give all the conclusions the sequence number of the streams, put all the outputs in one stream "print" and, there, save the list of any lines out of order so that the printout is what you want.

In the case of a β€œreal” application (that is, there is no trivial test application that uses threads incorrectly), where threads do a lot of work in parallel on sequential buffers, the order of which must be kept, forcing threads to wait for each other is usually not a reasonable option. In the usual way, use sequence numbers and reassemble the buffer stream afterwards.

+2
source

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

How else will you do this, given that thread 4 can end long before thread 1?

+1
source

Use a lock. If you can use boost, for example,

 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 scoped_lock you can use lock_guard .

0
source

Source: https://habr.com/ru/post/1397082/


All Articles