2011-08-19 63 views
0

所以我有這樣的日誌類:如何使線程安全支持`<<`操作的Log類?

#include <iostream> 
#include <sstream> 
#include <boost/circular_buffer.hpp> 
#include <boost/foreach.hpp> 

class FlushInternal; 

class Log 
{ 
public: 

    static FlushInternal* endl; 

    Log(int log_length) 
    { 
     i = 0; 
     messages_buffer = new boost::circular_buffer<std::string>(log_length); 
    } 

    template <class T> 
    Log &operator<<(const T &v) 
    { 
     current_message << v; 
     return *this; 
    } 

    Log &operator<<(std::ostream&(*f)(std::ostream&)) 
    { 
     current_message << *f; 
     return *this; 
    } 

    Log &operator<<(FlushInternal*) 
    { 
     ++i; 
     messages_buffer->push_back(current_message.str()); 
     clean_stringstream(current_message); 
     is_filled(); 
     return *this; 
    } 

    boost::circular_buffer<std::string> *messages_buffer; 

private: 
    int i; 
    std::stringstream current_message; 

    void is_filled() 
    { 
     if (i >= messages_buffer->capacity()) 
     { 
      i = 0; 
      BOOST_FOREACH(std::string s, *messages_buffer) 
      { 
       std::cout << ++i << ": " << s << " ;" << std::endl; 
      } 
      i = 0; 
     } 
    } 

    void clean_stringstream(std::stringstream &message) 
    { 
     message.flush(); 
     message.clear(); 
     message.seekp(0); 
     message.str(""); 
    } 
}; 

FlushInternal* Log::endl = 0; 

,我可以使用它像這樣:

#include <log.h> 
int main() 
{ 
    Log l(2); 
    l << "message one: " << 1 << Log::endl; 
    l << "message two:" << " " << 2 << Log::endl; 
    l << "message " << "three: " << 3 << Log::endl; 
    l << "message" << " " << "four: " << 4 << Log::endl; 
    std::cin.get(); 
} 

這將輸出:

1: message one: 1 ; 
2: message two: 2 ; 
1: message three: 3 ; 
2: message four: 4 ; 

正如你看到的,我可以有作爲許多<<正如我想在每個日誌消息中。我希望能夠同時在多個線程中使用一個Log類的實例。所以,我有這樣的事情(僞代碼編譯,運行,但沒有任何痕跡。):

#include <boost/thread.hpp> 
#include <log.h> 

Log *l; 

void fun_one() 
{ 
    *l << "message one: " << 1 << Log::endl; 
    *l << "message two:" << " " << 2 << Log::endl; 
} 

void fun_two() 
{ 
    *l << "message " << "three: " << 3 << Log::endl; 
    *l << "message" << " " << "four: " << 4 << Log::endl; 
} 

int main() 
{ 
    l = new Log(2); 
    boost::thread(fun_one); 
    boost::thread(fun_two); 
    std::cin.get(); 
} 

因此,大家可以看到我想要的消息被插入到日誌中multythreaded功能。我想知道 - 如何讓我的日誌cclass支持這個?

+0

我記得Qt有'qDebug()'線程安全的。也許你可以參考一下。 – neuront

+1

qDebug()不是線程安全的 – frisco

回答

3

由trojanfoe鏈接的方法幾乎是規範的。基本上爲最左邊的運算符創建一些臨時的東西,累積所有東西,並在析構函數中輸出消息以獲得臨時的東西。

唯一的問題是這個累加器的確切機制。這個示例使用了ostringstream,但我也看到了直接使用的日誌文件ofstream(需要鎖定才能確保輸出在一行中結束)。

創建ostringstreams在某些平臺上相對昂貴,因爲它們可能需要鎖定和複製一些與內部區域有關的事情。您可以重新實現有趣類型的< <運算符,但我會首先測試ostringstream方法。

一個有用的優化是在臨時構造的時候確定是否將發射蹤跡(例如,是否在該特定水平上啓用了追蹤),並且在該情況下根本不創建臨時的膽量 - 所有插入操作都是空操作。

3

這裏有一個辦法:

http://drdobbs.com/cpp/201804215

它基本上建立在每次執行時記錄一個新ostringstream對象,這使得它線程安全的。我不能說我對此非常感興趣,因爲它對我來說似乎有點笨拙。

您可能會看看Qt日誌記錄類,因爲他們支持<< operator,但我不確定線程​​安全。

相關問題