2012-03-08 50 views
2

我有一個C++應用程序,我在其中創建pthread以運行用戶提供的功能。我希望能夠在線程退出時以某種方式發出警報,以便我可以從我用來保持線程的pthread數組中移除它。有沒有辦法做到這一點,或者該功能是否應該設置一些「魔法值」。因爲我產生pthread的主代碼是一種runloop,所以我可以輕鬆地檢查退出條件。pthread退出時運行函數


此外,正在使用std::vector<pthread_t> overdoing來跟蹤我的線程是否超載?線程的數量不一定是任何常數,許多線程或很少可以運行。或者是否有另一個STL容器適合這些添加和刪除(總是在一端添加,幾乎在任何地方刪除)。有沒有其他的結構來跟蹤pthreads?堆棧或列表是否在這裏?還是一個標準的C陣列,慷慨的最大好處?由於問題的性質,我還可以維護一個固定大小的工作線程數組,我向其傳遞必須執行的用戶函數。這是一個好的解決方案嗎?

對不起,長期以來困惑的問題,但我只使用動態語言的線程,這永遠不會是一個問題。


EDIT(12年3月8日): 閱讀@ jojojapan的回答後,我決定使用某種形式的線程池。在我的結構中,我有一個生產者(runloop中的一個線程)和許多消費者(池中的工作線程)。是否有爲多線程單生產者許多消費者使用的數據結構?或者我只是使用std::queuepthread_mutex_t就可以了?你可能要考慮

+0

當你說「運行用戶提供的功能」,你是誰寫的線程funcs? – Duck 2012-03-08 04:27:34

+0

動態語言?你的意思是GC語言;)。 – 2012-03-08 04:28:59

+0

@Duck:不,我正在寫一個庫,使用它的程序員寫這些函數。 – Linuxios 2012-03-08 13:52:27

回答

3
  1. 一種選擇是沒有真正結束,刪除線程,一旦他們完成了任務,而是讓他們活着,讓他們等待新的任務分配給他們。你可以做兩件事情做到這一點:

    1. 使用的(幾乎)無限循環在線程
    2. 使用併發隊列或其他技術,使他們等待的信號由另一個線程被賦予。設計模式和策略在幾個SO問題中進行討論,例如this one
  2. 如果你真的想一旦線程結束髮送信號,您可以使用pthread_cond_t並在其上調用pthread_cond_signal一個線程到達其return聲明之前。當然,假設有一些其他線程正在運行,等待這些信號,並通過從矢量中刪除相應的線程來作用於它們。有關使用的詳細信息在相應的手冊頁上進行了說明,但也在this SO post中進行了說明。

編輯相關意見和問題的編輯部分:

  1. 關於工作線程的數量:這取決於資源使用的最由線程。如果這些線程所做的大部分工作是計算和一點內存訪問,換句話說,如果它們是CPU限制的,那麼使用盡可能多的線程是有意義的,因爲CPU可以維護多個線程(具體來說,有一定數量的內核,和每個內核的(硬件)線程的數量,在你的CPU開始減速之前,它們可以運行。你正在創建的線程(軟件線程)應該是大約一樣多,或者多一些(最多兩倍)硬件線程根據what @Tudor says here))是合理的)。但是,如果線程大量使用內存(內存綁定)或硬盤(IO綁定)或其他資源(如網絡,NFS或其他服務器),則可能需要按順序減少線程數)不要讓他們互相阻礙,(b)不要給某些資源帶來不合理的負擔。確定正確的線程數可能是一個實驗問題,並且保持數字可配置通常是一個好主意。

  2. 關於存儲工作任務的最佳數據結構:我在上面引用的帖子的評論中提到的concurrent bounded queue可能非常好。雖然我沒有嘗試過。但是,如果您想簡單起見,如果使用信號/互斥技術正確保護它們,標準std::queue或甚至簡單地std::vector不是一個不錯的選擇。

+0

感謝您的回答。你的第一個選擇很有意義。只有兩件事:一,你認爲我應該擁有多少工作者線程,以及二,我應該使用什麼數據結構來存儲需要執行的調用? (用'pthread_mutex_t'或一些特殊的線程隊列類鎖定的'std :: queue')。另外,我還會提出這個問題,有一個生產者和任何數量的消費者。 – Linuxios 2012-03-08 14:02:51

1

請考慮完全更改策略並使用現有的線程池庫。他們會爲你做這項工作,你將會節省很多不那麼有趣的調試。

Boost.thread池是其中之一,link

1

一個簡單的方法就是使用管道。

在產卵線程之前打開管道。傳遞管道fd作爲線程數據的一部分。在線程退出之前,它將pthread_self()寫入管道。管道讀端有主線或單線。它讀取死線程的tid並立即執行pthread_join。 (如果它是一個單獨的收割線程,它可以阻止讀取管道;如果它主要是使其成爲您的選擇/輪詢或其他任何部分)

這使您可以靈活地不使用數據結構如果不想要,可以保存TID。如果你想保存它們,那麼列表或地圖是比矢量更好的選擇。

如果您主要啓動線程和一個單獨的'收割者'線程收集它們,並且您想要將它們保存在某個結構中,那麼您將需要同步訪問這兩者之間的結構。

+0

管道看起來像一個相當重的工具,只用於在同一進程的兩個線程之間傳遞TID。我傾向於使用已完成的TID和pthread_cond_signal的共享列表來通知收割者已將新的TID添加到列表中。 – 2012-03-08 05:28:00

+1

管道不是特別重的重量,在這種情況下,它在N個螺紋上分攤。在PIPE_BUF大小下,數據自動同步。在管道複製的一點點花費來它的相對容易使用。 – Duck 2012-03-08 05:49:48