我正在使用一些遊戲項目的多線程代碼,並且厭倦了通過兩個線程使用cout創建的stdout嘔吐物來排序,以便在同一時間調試消息。我做了一些研究,並在提出「某些事情」之前盯着牆壁一兩個小時。以下代碼使用SFML進行計時和線程處理。 SFML互斥鎖只是將窗口中的關鍵部分封裝起來。線程安全cout技術。我錯過了什麼嗎?
頁眉:
#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元素,就會調用重載的操作符,互斥鎖被鎖定,流被刷新。
爲了驗證目的,我在輸出中添加了一些time/thread id調試信息。到目前爲止,我的測試表明這種方法是有效的。我有幾個線程用多個參數敲擊cout,並且所有內容都以正確的順序出現。
從我在研究這個問題時讀到的內容來看,在cout中缺少線程安全似乎是人們在冒險進入線程化編程時遇到的一個相當常見的問題。我試圖弄清楚的是,如果我使用的技術是解決這個問題的簡單方法,或者我認爲我很聰明,但錯過了一些重要的東西。
根據我的經驗,當用來描述編程的時候,聰明這個詞只是延遲疼痛的代碼字。我在這裏做些什麼,或者只是在周圍追逐糟糕的黑客?
謝謝!
它運作的事實是純粹的運氣。只有時間和線程ID的輸出受互斥量保護。在'OUTHACK'和'val1'之間潛入另一個線程是完全可能的。 – 2012-03-02 02:25:11
首先考慮寫入'ostringstream',然後將內容在一個操作中轉儲到'cout'。 ''cout'通常是線程安全的,只是每次調用的鎖定都很明顯,每個'<<'操作都是一個獨特的調用....這樣,應用程序代碼中就不會再有額外的鎖定 - 這隻能減少並行性。 – 2012-03-02 02:28:01
相關:[是cout同步/線程安全嗎?](http://stackoverflow.com/questions/6374264/is-cout-synchronized-thread-safe/6374525#6374525) – legends2k 2014-06-06 11:49:10