2013-10-02 57 views
3

我打算寫一個C++網絡應用程序,其中:跨線程分配好分配器和免費

  1. 我使用一個單獨的線程來接受TCP連接,並從中讀取數據。我打算使用epoll/select來做到這一點。數據被寫入緩衝區,使用某些競技場分配器,如jemalloc分配。
  2. 一旦來自單個TCP客戶端的足夠數據形成協議消息,數據就會發布在環形緩衝區中。環形緩衝區結構包含用於連接的fd和指向包含相關數據的緩衝區的指針。
  3. 工作線程處理來自環形緩衝區的條目並將一些結果數據發送到客戶端。在處理完每個事件後,工作線程釋放實際的數據緩衝區,將其返回給競技場分配器以供再次使用。

我沒有詳細說明發布者如何通過它向工作線程顯示寫入的數據。

所以我的問題是:是否有任何分配器優化這種行爲即在一個線程上分配對象並釋放另一個線程?

我特別擔心必須使用鎖來將內存返回到不是線程關聯競技場的競技場。我也擔心虛假共享,因爲生產者線程和工作線程都會寫入同一個區域。看起來像jemalloc或tcmalloc都沒有爲此優化。

回答

2

在開始爲多線程應用程序實現高度優化的分配器之前,首先應該使用標準的newdelete運算符來實現。在正確實施應用程序之後,可以移動以解決通過分析發現的瓶頸。

如果你去的地方很明顯,標準newdelete分配器是一個瓶頸應用程序的階段,下面是我使用的方法:

假設:線程的數量是固定和靜態創建。

  • 每個線程都有自己的競技場。
  • 從舞臺上取得的每個物品都有一個參考,它回到它來自的舞臺。
  • 每個競技場都有一個單獨的垃圾清單爲每個線程。
  • 當一個線程釋放一個對象時,它返回它來自的舞臺,但被放置在線程特定的垃圾列表中。
  • 實際擁有競技場的線程將其垃圾列表視爲真正的空閒列表。
  • 定期地,擁有一個競技場的線程執行一個垃圾收集過程,將對象從其他線程垃圾列表中摺疊到真正的空閒列表中。

「定期」垃圾回收通道不一定是基於時間的。例如,垃圾的一個子集可以在每次分配時免費獲得。

+0

感謝您的回答。你的假設是正確的。我從一開始就開始了所有的話題,他們的號碼從不改變。這似乎是一件好事,嘗試。就像你注意到的,我沒有做任何基準測試。在開始優化任何事情之前,我肯定會這樣做。 – Rajiv

+0

鎖爭用不應該是太多的問題。與處理圖像數據所花費的時間相比,鎖必須保持的時間非常短 - 只需將足夠小的「fd +緩衝區指針」結構體推送到您使用的任何隊列/容器即可。與將它們返回某個池供重新使用一樣。 –

+0

@MartinJames:這個問題本身比提問者的用例具有更廣泛的適用性。我已經警告提問者不要試圖實現這些複雜的事情,除非應用程序被證明需要它。其他人的應用程序可能需要這樣的東西,他們的搜索可能會把他們帶到這裏。 – jxh

2

處理內存分配和釋放問題的最好方法是不處理它。

您提到了一個環形緩衝區。這些通常是固定的大小。如果您可以爲協議消息提供固定的最大大小,則可以在程序啓動時分配您將需要的所有內存。解除分配時,保留內存但將其重置爲新的狀態。

現在,您的程序可能需要在處理每條消息時分配和釋放內存,但這將在每個線程中完成,而跨線程問題不會發揮作用。

即使您的郵件最大大小太大,如果您可以分配最多郵件將使用的內存量並預留了處理程序以便在必要時分配更多內存,也可以進行預分配。

+0

如果所有線程均對稱運行,則此方法運行良好。但是如果設計是這樣的,某些線程總是分配總是由永遠不分配這些類型的線程釋放的某些類型,這種技術會使程序像內存泄漏一樣運行。 – jxh

+0

感謝您的建議。我的應用程序處理不同大小的圖像。我的環形緩衝區會預分配所有對象,如您注意到的。這需要不必創建新對象並釋放它們。除此之外,環形緩衝區條目還包含指向包含圖像的緩衝區的指針。這些緩衝區不能預先分配,因爲最大大小限制太高。 – Rajiv