我正在尋找一種方法在我的C++項目中執行異步和線程安全日誌記錄,如果可能的話,將其記錄到一個文件中。我目前使用cerr
和clog
作爲任務,但由於它們是同步的,因此每次記錄日誌時執行都會暫停。這是一個相對圖形很重的應用程序,所以這種事情很煩人。C++中的異步線程安全日誌記錄
新記錄器應該使用異步I/O來擺脫這些暫停。線程安全也是可取的,因爲我打算很快添加一些基本的多線程。
我認爲每線程一個文件的方法,但這看起來會使日誌成爲一場惡夢。有什麼建議麼?
我正在尋找一種方法在我的C++項目中執行異步和線程安全日誌記錄,如果可能的話,將其記錄到一個文件中。我目前使用cerr
和clog
作爲任務,但由於它們是同步的,因此每次記錄日誌時執行都會暫停。這是一個相對圖形很重的應用程序,所以這種事情很煩人。C++中的異步線程安全日誌記錄
新記錄器應該使用異步I/O來擺脫這些暫停。線程安全也是可取的,因爲我打算很快添加一些基本的多線程。
我認爲每線程一個文件的方法,但這看起來會使日誌成爲一場惡夢。有什麼建議麼?
這是非常可能和實用的。我怎麼知道?我在上一份工作中寫下了這些。不幸的是(對我們而言),他們現在擁有代碼。 :-)不幸的是,他們甚至沒有使用它。
我打算在不久的將來編寫一個開源版本。同時,我可以給你一些提示。
由於您使用的是隊列,因此它本質上是線程兼容的。但是,您仍然希望在寫入隊列時添加一些類似互斥體的保護,以便給定日誌「更多內容」;類型操作仍然是線性原子的。
玩得開心!
我認爲正確的做法不是每個線程一個文件,而是每個文件一個線程。如果系統中的任何一個文件(或一般資源)只能被一個線程訪問,則線程安全編程變得非常容易。
那麼爲什麼不讓Logger成爲專用線程(或者多個線程,每個文件一個,如果你在不同的文件中記錄不同的東西),在所有其他線程中,寫入日誌會將消息放在輸入隊列中在相應的Logger線程中,在完成寫入前一條消息之後它將會到達它。它只需要一個互斥體來保護隊列在Logger正在讀取事件時添加一個事件,並且Logger在其隊列爲空時等待一個condvar。
您可以在不使用帶有無鎖隊列的互斥體的情況下離開。條件變量雖然更加不同。根據收費情況,你可能更喜歡旋轉,而不是去睡覺,以後再覺醒。這也取決於你是否有空閒的核心:) – 2010-05-28 16:07:32
如果我們的系統中有一些繁忙的東西在等待,看門狗會殺死整個應用:) – Cubbi 2010-05-29 16:53:36
你有沒有考慮過使用日誌庫。
有幾個可用的,我最近發現Pantheios,它真的好像很不可思議。
它更像是一個前端記錄器,您可以自定義使用哪個系統。它可以與ACE
或log4cxx
交互,例如它看起來很容易使用和配置。主要優點是它使用安全的操作員,這總是很棒的。
如果你只是想要一個準系統日誌庫:
選擇任何:)
我要指出,這是可以在C++中實現無鎖隊列,並且它們非常適合日誌記錄。
嗯,我不認爲我想引入任何這些。前兩個看起來有些過火,後者在其評論中有很多性能問題,這是他們沒有將其添加到Boost集合的原因之一。 – Electro 2010-05-28 16:25:33
我注意到這1年+舊線程。也許我寫的異步記錄器可能是有趣的。
http://www.codeproject.com/KB/library/g2log.aspx
G2log使用受保護的消息隊列轉發日誌記錄到後臺工作,慢的磁盤訪問。
我試着用無鎖隊列增加了LOG調用的平均時間,但減少了最壞情況下的時間,但是現在我正在使用受保護的隊列,因爲它是跨平臺的。它在Windows/Visual Studio 2010和Ubuntu 11.10/gcc4.6上進行了測試。
它作爲公共領域發佈,所以你可以用它做任何你想要的,沒有附加任何字符串。
如果日誌記錄不會導致任何阻塞(例如,打印調試競態條件......嘿,它的工作原理很簡單!),我通常會做的事情就是使用線程本地消息隊列來存儲帶有時間戳的令牌(在這種情況下可能更好地使用異步IO直接輸出它)。如果您需要這些數據,您只需稍後對輸出進行排序,對於常規日誌記錄來說相當麻煩,但它具有儘可能最低的同步量:nil。 – Voo 2011-11-26 13:29:22
重要的是當然不僅要保證線程安全以及最小的阻塞,還要確保軟件崩潰時的日誌條目在文件中(分段錯誤,浮點錯誤等)。 G2log規定,通過使用信號處理程序,如果出現「致命信號」,則在信號繼續(並中止程序)之前將排隊的條目刷新到文件 – 2011-11-26 16:31:48
@KjellHedström - 按照此鏈接http:// stackoverflow中的步驟操作。 com/help/user-merge讓你的賬戶合併。 – ChrisF 2013-03-12 23:53:16
我有同樣的問題,我相信我找到了完美的解決方案。我向你展示了一個名爲loguru的單頭庫:https://github.com/emilk/loguru
它簡單易用,便於攜帶,可配置,基於宏,並且默認情況下不會產生任何問題(對於那種甜美的編譯時間)。
不會有互斥意味着如果一個線程已經試圖寫入,它必須旋轉直到它被解鎖?這有什麼幫助? – Electro 2010-05-28 15:54:33
我肯定不會延遲對象到流中的轉換。把它放在另一個線程意味着不得不同步它......這可能會像地獄一樣受到傷害。 – 2010-05-28 15:59:47
@電子 - 不旋轉,但阻止。但是如果你沒有進行字符串處理,那麼加載隊列的時間間隔非常短。字符串處理由日誌記錄線程完成。 @Matthieu,在加載隊列時,實時進行字符串處理會比任何互斥鎖傷害更多。 – 2010-05-28 16:13:53