2014-01-06 192 views
1

我想實現一個快速記錄器,它包含日誌條目,並且當某個觸發器到達時,它將刷新最後的X條消息。我可以「強制」線程喚醒嗎?

這樣的想法是保持在一個循環緩衝區中的所有消息,一旦我們有觸發,推它的ID到隊列中,而另一線程監視(在所有系統中的一個線程)。此線程將返回X消息並刷新它們。我知道如何處理在我嘗試刷新時正在寫入的消息,在刷新正在刷新的消息之前已被覆蓋的消息,而我試圖更新它們等。

我的問題是,例如我有20個線程寫消息,只有10個內核,在2個「writer」線程執行之間的時間差,所有的緩衝區都會被覆蓋好幾次。

有沒有什麼辦法可以讓「我的」線程「強制」「編寫器」線程執行(或給它是時間片?我猜不,但是仍然... 你能建議任何其他方式/設計來克服這個問題

+1

取決於,但一次有多個線程寫入硬盤驅動器會在硬盤驅動器達到飽和CPU處理速度之前很久就會飽和硬盤驅動器的速度。爲了簡單起見,我只有一個寫線程: - /。在任何一種情況下,互斥鎖或文件鎖將有助於確保只有1(fifo)線程可以訪問緩衝區或寫入位置。 – IdeaHat

+0

@MadScienceDreams:是的,我有一個作家(相應地更新了問題)。但問題仍然存在,筆者有機會刷新它 – yosim

+0

可以給該線程優先級更高,所以只要用信號(通過條件變量之前緩衝區被覆蓋,互斥,信號量,讀者,作家鎖,無論你想要什麼),系統調度程序將執行該線程。請注意,您的問題可以通過更好的設計得到更好的解決。如果你的緩衝區在沒有你的控制的情況下被覆蓋,那麼你需要重新思考你的日誌機制。 – Shahbaz

回答

0

我寫過類似的東西,其中對日誌方法的調用實際上被放置在另一個線程(T-Logger)監視的隊列中,這樣就可以讓其他線程不必調用底層日誌的API和低延遲的應用效果很好。

如果你想明確地緩衝,然後觸發寫那麼我還是建議你從做所有的寫操作Ë線,如T-Logger然後用某種conditional variable來通知T-Logger,它現在應該去寫在隊列中的項目的基本日誌文件。

正如問題評論中提到的,您應該避免讓多個線程嘗試執行IO操作。 IO非常慢,並且讓所有線程試圖寫入文件都會導致它們放棄CPU週期等待IO完成。

+0

@Shahbaz - 真。我稍微改了一下我的答案。 – Sean

+0

是的,我將只有一個線程正在寫入。主要問題是,條件變量是否確保線程一旦發出信號就會喚醒?我沒能找到這樣的保證(雖然有可能我沒看夠深...) – yosim

+0

@yosim - 條件變量將導致正在等待它轉變爲「可運行」狀態的任何線程,在某些時候,操作系統會在CPU上安排線程並運行它。你永遠不會得到一個解決方案,這將導致等待線程立即開始運行,因爲操作系統將不得不考慮所有線程的調度。 – Sean

1

據我所知,只要隊列中有新的ID可用,您就想恢復您的線程。這可能會導致鎖定原語 - 您的編寫器線程應該睡眠,直到觸發器線程通知爲止。如何實現這種行爲取決於你正在使用的多線程框架。

例如,在C++ 11中,您可以看看std::condition_variable

編輯。正如評論中所提到的,磁盤IO速度很慢,所以您需要在寫入程序線程中將消息提取到內存,然後纔將它們寫入磁盤。在IO期間,緩衝區可以被到達的消息覆蓋。

+0

信號是否是當前睡在一個條件的線程,gaurantees它會醒來?我試過用互斥體,它沒有工作,我想的條件,但我沒能找到這樣的保證。 – yosim

+0

條件變量專門旨在處理這種情況,所以該線程將醒來!事實上,即使[假的喚醒,(http://www.cplusplus.com/reference/ condition_variable /溼ition_variable/wait /)是可能的一些實現。有可能通過互斥體實現條件,但互斥體主要用於「互斥」。 –

0

聽起來像使用信號量的經典案例,使用循環緩衝區的長度進行初始化。來自需要記錄東西的線程的日誌調用在繼續之前必須從信號中獲取一個單元,並且當日志線程從隊列中提取一個條目時,該線程會通知信號量。如果緩衝區用完,任何嘗試登錄的線程都會阻塞,直到有足夠的日誌條目空間。

顯然,對於日誌條目的循環緩衝器/隊列/不管容器必須是線程安全的。

+0

沒有信號量,你可以達到同樣的效果。只保留你刷新的最後一個索引,如果你的下一個索引是這個索引 - 你應該在緩衝區滿時阻塞/做其他的事情。 但是,這有兩個主要缺陷:1,記錄器不能阻塞。但更重要的是,並非所有消息都需要刷新。很有可能我們幾乎沒有閃動的手倒立,然後沖洗一切。 – yosim