Поточно-безопасный метод cout. Я что-то упустил?

Я работаю с некоторым многопоточным кодом для игрового проекта, и мне немного надоело перебирать поток stdout, созданный двумя потоками, использующими cout для одновременной отладки сообщений. Я провел небольшое исследование и час или два смотрел на стену, прежде чем придумать "что-то". Следующий код использует SFML для учета времени и потоковой передачи. Мьютексы SFML - это просто обернутые критические секции в окнах.

Заголовок:

#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);

Реализация:

#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;
}

Использование:

cout<<OUTHACK<<val1<<val2<<val3....<<endl;

Хорошо, это работает с помощью перегруженного оператора вставки, который устанавливает безопасность потоков, блокируя итератор в статическом объекте, а затем очищая буфер. Если я правильно понимаю процесс (я в основном программист-самоучка), cout обрабатывает элементы своей цепочки вставки от конца до начала, передавая переменную ostream вниз по цепочке для каждого элемента, который будет добавлен к потоку.Как только он достигает элемента OUTHACK, вызывается перегруженный оператор, мьютекс блокируется, а поток сбрасывается.

Я добавил к выходным данным некоторую отладочную информацию по времени / идентификатору потока для проверки. Пока что мое тестирование показывает, что этот метод работает. У меня есть несколько потоков, обрушивающихся на cout с несколькими аргументами, и все получается в правильном порядке.

Из того, что я прочитал во время исследования этой проблемы, отсутствие безопасности потоков в cout кажется довольно распространенной проблемой, с которой люди сталкиваются, когда начинают заниматься многопоточным программированием. Я пытаюсь понять, является ли техника, которую я использую, простым решением проблемы, или я думаю, что я умен, но упускаю что-то важное.

По моему опыту, слово «умный», когда оно используется для описания программирования, является просто кодовым словом для обозначения отсроченной боли. Я что-то тут понял, или просто гоняюсь за паршивыми хакерами по кругу?

Спасибо!

9
задан Chris 2 March 2012 в 02:21
поделиться