7

Imagine you have two threads. The first thread tries to print integer as decimal using std::dec:

std::cout << std::dec << 123 << std::endl; 

The second thread tries to print integer as hexadecimal using std::hex:

std::cout << std::hex << 0x321 << std::endl; 

Is it guaranteed that 123 will be printed as decimal and 0x321 will be printed as hexadecimal? If it is not, how do I do proper std::cout formatting in multithread environment?

C++20 has std::osyncstream. But what can we use before C++20?

12
  • std::mutex Commented Aug 12, 2020 at 12:46
  • 3
    Does this answer your question? How to easily make std::cout thread-safe? Commented Aug 12, 2020 at 12:46
  • @bolov, what if use third party library that has its own threads? Commented Aug 12, 2020 at 12:47
  • 1
    There is no solution without either a mutex wrapping the whole access to std::cout, or a temporary buffer and then only protecting the final write by a mutex. If you are worried about temporary buffer performance in embedded, then provide a custom allocator to std::stringstream which pre-allocates up to n bytes inline (in embedded buffer), and only exceeding allocations in heap instead. Commented Aug 21, 2020 at 8:27
  • 1
    @anton_rh: If I am reading it correctly, osyncstream itself does not change cout to have mutual exclusion properties. It is a type that can act like a synchronous stream. So it doesn't solve the 3rd party issue you are raising. Commented Aug 22, 2020 at 5:04

2 Answers 2

3
+100

From the get-go, this isn't an option with std::cout.

If you just want to use a different object a simpel way is just use stringstream for each 'compound' needed eg.:

std::cout << (std::ostringstream{} << std::hex << 0x321 << std::endl).str(); 

Alternatively you can make your own stream class that just forwards everything to std::cout on destruction (eg. you could have std::ostringstream as a member or inherit it):

~MyStringStream(){ std::cout << str(); } 

I wouldn't recommend changing this fact on the actual std::cout because others will not expect std::cout to behave in this or that different way. However with that being said I think it is possible with redirection, so I created a way to showcase this (somewhat of a hack: I consider everything that does something like this a hack) and how to make this possible. Please note this isn't a finished solution at all, it just shows how to get std::cout to go through your own stream class, which then needs to be implemented/overridden 'correctly', made thread-safe and then added the neccesary synchronizations, or however you plan to get that extra level, etc. Please also note I haven't considered how this interferes with the std::cout tie'ed streams (eg. std::in, std::err), but I guess it's not a big deal.

Try it yourself on godbolt

#include <utility> #include <string> #include <iostream> #include <sstream> std::stringstream new_out; class SyncedStreamBuf : public std::stringbuf { public: SyncedStreamBuf(){} virtual int sync() override { new_out << "From override: " << str(); str("");//empty buffer return 0;//success } }; class SyncedStream : public std::ostream { public: SyncedStream() : std::ostream(&syncedStreamBuf_){ } private: SyncedStreamBuf syncedStreamBuf_; }; SyncedStream my_stream; int main() { std::streambuf* cout_buff = std::cout.rdbuf(); // save pointer to std::cout buffer std::cout.rdbuf(my_stream.rdbuf());//redirect cout to our own 'stuff' static_cast<std::ostream&>(new_out).rdbuf(cout_buff);//put cout's buffer into a new out stream new_out << "test: new_out now prints to stdout\n"; std::cout << "some message\n";//<--now goes through our overridden class std::cout.flush(); std::cout << "you will see this message - didn't flush\n"; } 

Output:

test: new_out now prints to stdout From override: some message 
Sign up to request clarification or add additional context in comments.

2 Comments

Buffering in a separate buffer alone isn't going to suffice. A statically scoped mutex around the access to std::cout is still required in order to prevent interleaving on a character-by-character base. Furthermore, your first example didn't flush due to the intermediate cast to a string, loosing the usual side effects of std::endl.
@Ext3h Great comment, thank you. Im not sure if you saying it's possible or impossible with this method ? I still think it should be possible with redirection to own buffer.
0

Use a function to print output. A output will only be printed from this function. Use mutex inside this function.

OutputFunction(int form, const int& value) { std::lock_guard<std::mutex> m_OutputMutex; if(form == 0)// 0 means dec { std::cout << std::dec << value << std::endl; } elseif(form ==1) { std::cout << std::hex << value << std::endl; } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.