I am trying to capture the content written into std::cout stream to redirect it to a text file. For that, I intent to just follow the solution given in https://stackoverflow.com/questions/10150468/how-to-redirect-cin-and-cout-to-files:
std::ofstream out("out.txt");
std::cout.rdbuf(out.rdbuf()); //redirect std::cout to out.txt!
std::cout << "blabla" << std::endl; //output to the file out.txt
I understand from https://en.cppreference.com/w/cpp/io/cout that it is safe for two threads to write at the same time in std::cout. I am fully aware it does not mean that interleaving of text may not happen. My question: is this redirection of std::cout to std::ofstream still thread safe in a multi threading context ? My understanding is that std::ofstream is not thread safe by itself.
I did a test with my own implementation of the std::streambuf injected in std::cout and 5 threads writing on std:cout:
#include <iostream>
#include <thread>
#include <atomic>
using namespace std;
class StreamToLogRedirector:public
std::streambuf
{
public:
StreamToLogRedirector ():
counter (0)
{
}
std::streamsize
xsputn (char_type const *s, std::streamsize count)
override
{
counter++;
if (counter > 1)
{
std::cerr << "Counter " << counter << std::endl;
}
counter--;
return count;
}
int
overflow (int c)
override
{
counter++;
if (counter > 1)
{
std::cerr << "Counter " << counter << std::endl;
}
counter--;
return c;
}
private:
std::atomic < int >
counter;
};
int
main ()
{
StreamToLogRedirector
redirector;
std::cout.rdbuf (&redirector);
auto
a = std::thread ([](){
while (true) std::cout << "Write from A\n";}
);
auto
b = std::thread ([](){
while (true) std::cout << "Write from B\n";}
);
auto
c = std::thread ([](){
while (true) std::cout << "Write from C\n";}
);
auto
d = std::thread ([](){
while (true) std::cout << "Write from D\n";}
);
auto
e = std::thread ([](){
while (true) std::cout << "Write from E\n";}
);
a.join ();
b.join ();
c.join ();
d.join ();
e.join ();
return 0;
}
I can see that the counter is reaching 5, meaning that the functions StreamToLogRedirector are called in parallel.
My conclusion is that the thread safety aspect is not handled at the level of the std::cout object std::ostream, but at the level of the underlying std::streambuf. If std::ofstream is not thread safe, that mean that redirecting std::cout to std::ofstream is now making the usage of std:cout not thread safe by itself.
Is my conclusion correct or I am missing something ?
Thank you, Simon