2013-02-22 68 views
8

我有OpenMP線程通過cout和cerr寫入控制檯。這當然是不安全的,因爲輸出可以交錯。我可以做類似多個線程寫入std :: cout或std :: cerr

#pragma omp critical(cerr) 
{ 
    cerr << "my variable: " << variable << endl; 
} 

,類似的做法在Valgrind的DRD手冊(​​3210)涉及從STD派生一個類解釋說這將是更好,如果能有一個線程安全的版本替換CERR :: ostreambuf 。理想情況下,最後我會用我自己的螺紋cerr來代替cerr,例如簡單地說:

tcerr << "my variable: " << variable << endl; 

這樣的類只要遇到「endl」就可以打印到控制檯。我不介意來自不同線程的線是否交錯,但每條線只能來自一個線程。

我真的不明白C++中的所有流是如何工作的,它太複雜了。有沒有人有這樣的課程,或者可以告訴我如何爲此目的創建這樣的課程?

+0

請不要暗示的printf ..;) – Wolfgang 2013-02-22 21:55:07

+0

*「這當然不是安全的」 * - 這是不是在C++ 11真正的,除非你採取故意的動作,使其真正。 – 2013-02-22 21:56:38

+0

你的頭銜說'cout'不是'cerr'。 – Barmar 2013-02-22 21:59:56

回答

0

你可以通過繼承std::basic_streambuf來做到這一點,並重寫正確的函數以使其線程安全。然後將這個類用於你的流對象。

8

您可以使用類似於字符串生成器的方法。創建一個非模板類:

  • 插入提供模板operator<<到這個對象
  • 內部構建成std::ostringstream
  • 毀滅轉儲內容

粗糙的方法:

class AtomicWriter { 
    std::ostringstream st; 
public: 
    template <typename T> 
    AtomicWriter& operator<<(T const& t) { 
     st << t; 
     return *this; 
    } 
    ~AtomicWriter() { 
     std::string s = st.str(); 
     std::cerr << s; 
     //fprintf(stderr,"%s", s.c_str()); 
     // write(2,s.c_str(),s.size()); 
    } 
}; 

作爲:

AtomicWriter() << "my variable: " << variable << "\n"; 

或者在更復雜的情況:

{ 
    AtomicWriter w; 
    w << "my variables:"; 
    for (auto & v : vars) { 
     w << ' ' << v; 
    } 
} // now it dumps 

您將需要添加更多的重載如果你想操縱器,您可以使用writefprintf更好地爲在析構函數中原子寫入,或std::cerr ,您可以概括以便將目標傳遞給構造函數(std::ostream /文件描述符/ FILE*),

+0

我想我還會添加一個'flush'成員,它與析構函數完全相同,並清除內部緩衝區。如果你願意,你可以重複使用相同的原子。有些人可能更喜歡在第二個例子中使用額外的範圍。 – 2013-02-22 22:59:11

+0

@MooingDuck:不知道要走什麼路...我明白你要求什麼,但是我發現範圍允許我在查看邏輯而不是痕跡時忽略內容(我們的日誌框架允許類似結構體)。也就是說,如果使用正確(即不要將邏輯與日誌記錄混合使用),範圍可用於分析內容並確保沒有真正的邏輯,之後我不需要嘗試解釋什麼是內部循環我正在研究整個功能的邏輯。 – 2013-02-22 23:35:09

20

正如其他人指出的,在C++ 11,std::cout線程安全的。

但是如果你使用它像

std::cout << 1 << 2 << 3; 

與不同的線程,輸出仍然可以交錯,因爲每個<<是一個新的函數調用可以通過另一個線程的任何函數調用preceeded。

爲了避免不交織一個#pragma omp critical - 這將鎖定一切 - 你可以做到以下幾點:

std::stringstream stream; // #include <sstream> for this 
stream << 1 << 2 << 3; 
std::cout << stream.str(); 

的三個電話寫123到流都只有一個線程發生在一個地方,非共享對象,因此不受任何其他線程的影響。然後,共享輸出流std::cout只有一個調用,其中項目123的順序已經固定,因此不會搞亂。

0

我沒有足夠的聲望發表評論,但我想發佈我的除了AtomicWriter類以支持std :: endl,並允許除std :: cout之外使用其他流。那就是:

class AtomicWriter { 
    std::ostringstream st; 
    std::ostream &stream; 
public: 
    AtomicWriter(std::ostream &s=std::cout):stream(s) { } 
    template <typename T> 
    AtomicWriter& operator<<(T const& t) { 
     st << t; 
     return *this; 
    } 
    AtomicWriter& operator<<(std::ostream&(*f)(std::ostream&)) { 
     st << f; 
     return *this; 
    } 
    ~AtomicWriter() { stream << st.str(); } 
};