I'm working with some multithreaded code for a game project, and got a bit tired of sorting through the stdout vomit created by two threads using cout for debuging messages at the same time. I did some research and stared at a wall for an hour or two before coming up with "something". The following code uses SFML for time keeping and threading. SFML mutexes are just wrapped critical sections in windows.
Header:
#include <SFML\System.hpp>
#include <iostream>
class OutputStreamHack
{
public:
OutputStreamHack();
~OutputStreamHack();
ostream& outputHijack(ostream &os);
private:
sf::Clock myRunTime;
sf::Mutex myMutex;
};
static OutputStream OUTHACK;
ostream& operator<<(ostream& os, const OutputStreamHack& inputValue);
Implementation:
#include <SFML\System.hpp>
#include <iostream>
#include "OutputStreamHack.h"
using namespace std;
OutputStreamHack::OutputStreamHack()
{
myMutex.Unlock();
myRunTime.Reset();
}
OutputStreamHack::~OutputStreamHack()
{
myMutex.Unlock();
myRunTime.Reset();
}
ostream& OutputStreamHack::outputHijack(ostream &os)
{
sf::Lock lock(myMutex);
os<<"<"<<myRunTime.GetElapsedTime()<<","<<GetCurrentThreadId()<<"> "<<flush;
return os;
}
ostream& operator<<(ostream& os, const OutputStreamHack& inputValue)
{
OUTHACK.outputHijack(os);
return os;
}
Usage:
cout<<OUTHACK<<val1<<val2<<val3....<<endl;
Ok, so the way this works is through an overloaded insertion operator that imposes thread safety by locking an iterator in a static object, then flushing the buffer. If I understand the process correctly (I am mostly a self taught programmer), cout processes elements of its insertion chain from the end to the beginning, passing an ostream variable down the chain for each element to be prepended to the stream. Once it reaches the OUTHACK element, the overloaded operator is called, the mutex is locked, and the stream is flushed.
I've added some time/thread id debugging info to the output for verification purposes. So far, my testing shows that this method works. I have several threads pounding cout with multiple arguments, and everything is coming out in the right order.
From what I have read while researching this issue, lack of thread safety in cout seems to be a pretty common problem that people run into while venturing into threaded programming. What I am trying to figure out is if the technique I am using is a simple solution to the problem, or me thinking that I am clever but missing something important.
In my experience, the word clever when used to describe programming is just a code word for delayed pain. Am I on to something here, or just chasing lousy hacks around in circles?
Thanks!
OUTHACK
andval1
. – Extramaritalostringstream
first, then dumping the content in one operation tocout
.cout
will generally be thread safe, it's just that the locking is obviously per call, and each<<
operation is a distinct call.... That way, there's no extra locking in your application code - which can only reduce parallelism. – Condescendence