Ok, we've built this "cout wrapper" that automatically serializes concurrent printing attempts. How does it work?
Let's do the same steps our pcout helper does in a manual manner without any magic. First, it instantiates a string stream and accepts the input we feed into it:
stringstream ss;
ss << "This is some printed line " << 123 << 'n';
Then it locks a globally available mutex:
{
lock_guard<mutex> l {cout_mutex};
In this locked scope, it accesses the content of string stream ss, prints it, and releases the mutex again by leaving the scope. The cout.flush() line tells the stream object to print to the terminal immediately. Without this line, a program might run faster because multiple printed lines can be bunched up and printed in a single run later. In our recipes, we will like to see all output lines immediately, so we use the flush method:
cout << ss.rdbuf();
cout.flush();
}
Ok, this is simple enough but tedious to write if we have to to the same thing again and again. We can shorten down the stringstream instantiation as follows:
stringstream{} << "This is some printed line " << 123 << 'n';
This instantiates a string stream object, feeds everything we want to print into it and then destructs it again. The lifetime of the string stream is reduced to just this line. Afterward, we cannot print it any longer, because we cannot access it. Which code is the last that is able to access the stream's content? It is the destructor of stringstream.
We cannot modify stringstream instance's member methods, but we can extend them by wrapping our own type around it via inheritance:
struct pcout : public stringstream {
~pcout() {
lock_guard<mutex> l {cout_mutex};
cout << rdbuf();
cout.flush();
}
};
This class is still a string stream and we can use it like any other string stream. The only difference is that it will lock a mutex and print its own buffer using cout.
We also moved the cout_mutex object into struct pcout as a static instance so we have both bundled in one place.