2012-01-10 26 views
1

我遇到了多線程中的問題,多線程模型是1個生產者 - N個消費者。多線程中對數據的引用跟蹤(多少/誰)

生產者所產生的數據(字符數據周圍200bytes每個),把它在固定大小的高速緩存(即2密耳)。數據與所有線程無關。它應用過濾器(已配置)並確定線程數量是否符合生成的數據。

生產者推動指針數據分成合格的線程隊列(僅指向數據的指針,以避免數據複製)。線程將deque並通過TCP/IP發送給它們的客戶端。

問題:因爲只有指針數據被提供給多個線程,當高速緩存變滿,主要生產要刪除的第一個項目(舊)。任何線程仍然可能引用數據。

可行之路:用原子粒度,當製片人決定了排位賽的線程數,它可以更新計數器和線程ID列表。

class InUseCounter 
{ 
    int   m_count; 
    set<thread_t> m_in_use_threads; 
    Mutex   m_mutex; 
    Condition  m_cond; 

public: 
    // This constructor used by Producer 
    InUseCounter(int count, set<thread_t> tlist) 
    { 
     m_count   = count; 
     m_in_use_threads = tlist; 
    } 

    // This function is called by each threads 
    // When they are done with the data, 
    // Informing that I no longer use the reference to the data. 
    void decrement(thread_t tid) 
    { 
     Gaurd<Mutex> lock(m_mutex); 
     --m_count; 
     m_in_use_threads.erease(tid); 
    } 

    int get_count() const { return m_count; } 
}; 

主chache

map<seqnum, Data> 
       | 
       v 
      pair<CharData, InUseCounter> 

當生產者將刪除它檢查計數器的元件,爲大於0時,它發送動作以釋放設置m_in_use_threads參考到螺紋上。

問題

  1. 如果在主緩存2MIL記錄,將有相等數量 的InUseCounter,所以互斥可變因素,在一個單一的過程中這個建議有2MIL互斥varible。
  2. 有大單數據結構來保持InUseCounter將 造成更多的鎖定時間去尋找和減少
  3. 什麼是對我的方法的最佳替代品,以找出引用和誰 都非常少引用鎖定時間。

提前感謝您的建議。

回答

4
  1. 200萬個互斥體是有點多。即使它們是輕量級鎖,它們仍然佔用一些開銷。
  2. InUseCounter放在一個單一結構中會導致線程在釋放記錄時引起爭用;如果線程沒有以鎖步方式執行,這可能可以忽略不計。如果他們頻繁發佈記錄並且爭用率上升,這顯然是一個表現下沉。
  3. 您可以通過讓一個線程負責維護記錄引用計數(生產者線程)並使其他線程通過單獨的隊列發回記錄發佈事件來提高性能,實際上,將生產者轉換爲記錄發佈事件使用者。當你需要刷新一個條目時,首先處理所有發佈隊列,然後運行你的發佈邏輯。您將需要處理一些延遲,因爲您現在正在排隊發佈事件,而不是立即嘗試處理它們,但性能應該會更好。

順便提一句,這與Disruptor框架的工作方式類似。這是高頻率交易的高性能Java(!)併發框架。是的,我在同一句話中說過高性能的Java和併發性。對高性能併發設計和實現有很多有價值的見解。

+0

啊,同樣的想法:)簡潔的參考! – 2012-01-10 08:43:45

0
  1. 是的,200萬互斥是矯枉過正。
  2. 1大結構將被鎖定更長時間,但將需要更少的鎖定/解鎖。
  3. 最好的方法是使用shared_ptr智能指針:它們似乎是爲此量身定製的。你不要自己檢查櫃檯,你只需清理指針。 shared_ptr是線程安全的,而不是它指向的數據,但對於1個生產者(作家)/ N個消費者(讀者)來說,這不應該是一個問題。
+0

我們認爲shared_ptr <>支持。這種方法的問題在於,如果消費者長期持有該參考。內存峯值可能會發生,生產者也會失去對數據破壞的控制。這可能適用於一小部分數據,對象的生命週期非常短。 – naveenhegde 2012-01-10 09:40:03

+0

@naveen:只要需要,消費者應該持有參考。如果數據在消費者仍在使用時被破壞,則會發生不好的事情。如果消費者在參考完成後仍然堅持參考,這是一個糟糕的消費者(並且它也不會設置參考計數) – stefaanv 2012-01-10 10:47:34

1

由於您已有一個Producer->Consumer隊列,因此一個非常簡單的系統就是擁有一個「反饋」隊列(Consumer->Producer)。

消費完一個項目後,消費者將指針返回給生產者,以便生產者可以刪除該項目並更新緩存的「自由列表」。

這樣,只有生產者觸及緩存內部,不需要同步:只有隊列需要同步。