2012-10-14 197 views
2

我需要一個用於我的應用程序的線程池,並且我希望儘可能地依賴標準(C++ 11或boost)內容。我意識到有一個非官方的(!)boost線程池類,它基本上解決了我需要的東西,但是我寧願避免它,因爲它不在boost庫本身 - 爲什麼在它之後仍然不在覈心庫中很多年?boost線程池

在本頁和其他地方的一些帖子中,人們建議使用boost :: asio來實現類似於線程池的行爲。乍一看,這看起來像我想做的事情,但是我發現我看到的所有實現都無法加入當前活動的任務,這使得它對我的應用程序無用。爲了執行一個連接,他們向所有的線程發送停止信號並隨後加入它們。但是,這完全消除了我的用例中線程池的優點,因爲這使得新任務需要創建一個新線程。

我想要做的是:

ThreadPool pool(4); 
for (...) 
{ 
    for (int i=0;i<something;i++) 
     pool.pushTask(...); 
    pool.join(); 
    // do something with the results 
} 

任何人都可以提出一個解決方案(除了使用SourceForge上的現有非官方的線程池)?在C++ 11或核心提升中有什麼可以幫助我嗎?

+0

你不想'boost :: threadpool'因爲它是非官方的? –

回答

0

加入一個線程均值停止,直到它停止,如果停止並且您想要爲其分配新任務,則必須創建一個新線程。所以在你的情況下,你應該等待一個條件(例如boost::condition_variable)來指示任務結束。所以使用這種技術很容易實現它使用boost::asioboost::condition_variable。每個線程調用boost::asio::io_service::run和任務將在不同的線程上進行調度和執行,並且在最後,每個任務將設置boost::condition_variable或事件遞減std::atomic以指示作業結束!那真的很簡單,不是嗎?

+0

對不起,當我說加入,我通常意味着等待任務(而不是線程)的終止。但通常,是的,我同意條件變量是一個解決方案。但是,現在在我的外循環的每次迭代中,我需要實例化條件變量。我不確定這是否是一項昂貴的操作?至於std :: atomic:我不知道父線程可以「等待」原子爲零嗎? – Dtag

+1

我只是說條件變量作爲示例,但您甚至可以使用其他技術,例如使用互斥鎖來訪問計數變量,並且當計數達到零時設置條件變量並且當它遞增時重置它。你已經知道解決方案! – BigBoss

1

讓每個任務類都來自具有「OnCompletion(任務)」方法/事件的任務。線程池線程可以在調用任務的main run()方法之後調用它。

等待完成單個任務很容易。 OnCompletion()可以執行任何需要的信號來指示始發線程,發出condvar信號,將任務排隊到生產者 - 消費者隊列,調用SendMessage/PostMessage API,Invoke/BeginInvoke等等。

如果一個oringinating線程需要等待多個任務全部完成,那麼可以擴展上面的內容並向池中發出一個「等待任務」。等待任務有其自己的OnCompletion來傳達其他任務的完成,並有一個線程安全的「任務計數器」(原子操作或鎖),設置爲要發佈的「主」任務的數量。等待任務首先發送到池,並且運行它的線程等待等待任務中的私有'allDone'condvar。然後將'主要'任務發佈到池中,其OnCompletion設置爲調用等待任務的方法,將任務計數器遞減至零。當任務計數器達到零時,實現此目標的線程將發出allDone condvar信號。等待任務OnCompletion然後運行,並表示完成所有主要任務。

這樣的機制不需要線程池線程的不斷創建/終止/加入/刪除,也不需要限制發送任務如何發送信號,並且可以根據需要發出任意數量的任務組。但是,您應該注意,每個等待任務都會阻塞一個線程池線程,因此請確保在池中創建一些額外的線程(通常不會有任何問題)。

1

這看起來像boost::futures的工作。文檔中的示例似乎正好展示了您正在尋找的內容。

3

乍一看,這看起來像我想做的事情,但是我發現我看到的所有實現都無法加入當前活動任務,這使得它對我的應用程序無用。爲了執行一個連接,他們向所有的線程發送停止信號並隨後加入它們。但是,這完全消除了我的用例中線程池的優點,因爲這使得新任務需要創建一個新線程。

我想你可能誤會了ASIO例如:

IIRC(它已經有一段時間),每個線程的線程池運行呼籲io_service::run這意味着有效的每個線程都有一個事件循環和調度。然後讓asio完成任務,使用io_service :: post方法將任務發佈到io_service,並使用asio的調度機制負責其餘部分。只要你不叫io_service::stop,線程池將繼續運行,使用與你開始運行時一樣多的線程(假設每個線程都有工作要做或已經被分配了一個io_service::work對象)。

所以你不需要需要爲新任務創建新線程,這將違背線程池的概念。