2012-08-23 41 views
0

我有以下用boost :: asio製作的線程池的最小示例。帶boost :: asio的ThreadPool不退出?

#include <queue> 
#include <map> 

#include <boost/shared_ptr.hpp> 
#include <boost/asio/io_service.hpp> 
#include <boost/thread/thread.hpp> 
#include <boost/asio.hpp> 
#include <boost/date_time/posix_time/posix_time.hpp> // remove me (only for io) 

class ThreadPool 
{ 
public: 
    void work_as_mainthread(void) { m_io_service.run(); } 

    ThreadPool(int poolSize = 4) : timer(m_io_service) 
    { 
     timer.expires_from_now(boost::posix_time::seconds(1)); // this line does not affect the problem 
     m_pWork.reset(new boost::asio::io_service::work(m_io_service)); 

     for (int i = 0; i < poolSize; ++i) 
      m_threadGroup.create_thread(boost::bind(&boost::asio::io_service::run, &m_io_service)); 
    } 

    ~ThreadPool() 
    { 
     m_pWork.reset(); 
     m_threadGroup.join_all(); 
    } 

private: 
    boost::asio::io_service m_io_service; 
    boost::asio::deadline_timer timer; 
    boost::shared_ptr<boost::asio::io_service::work> m_pWork; 
    boost::thread_group m_threadGroup; 
}; 

int main() 
{ 
    int n_threads = 2; 
    ThreadPool pool(n_threads); 
    pool.work_as_mainthread(); 
    // this line is never reached... 
    return 0; 
} 

如果你喜歡,你可以編譯它是這樣的:

g++ -Wall -g -lboost_thread -lboost_date_time -lboost_system main.cpp -o main 

是什麼讓我納悶的是,該計劃不會停止。我所做的是調用io_service :: run,但沒有任何「工作」。正如boost :: asio文檔中所說,沒有工作的io_services會自行退出。現在,爲什麼我的程序永遠不會退出?

+1

對於線程池實現,讀取[處理程序拋出的異常的影響]可能是值得的(http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/reference/io_service。 html#boost_asio.reference.io_service.effect_of_exceptions_thrown_from_handlers)並考慮[避免堆](http://think-async.com/Asio/TipsAndTricks?skin=clean.nat%2casio%2cpattern#Stopping_the_io_service_from_run)通過使用'boost ::可選'而不是'boost :: shared_ptr'。 –

回答

3

當您創建boost::asio::io_service::work對象時,會使io_service無法完成。

// This line keeps the io_service running 
m_pWork.reset(new boost::asio::io_service::work(m_io_service)); 

如果你想讓它停下來,你將需要銷燬工作對象,像這樣:

// stop the worker(s) 
m_pWork.reset(); 

這是給你找到一個合適的時間/地點做到這一點。我建議打電話timer.async_wait(),然後在處理程序中,您可以重置您的工作對象,看看這一切應該如何一起工作。

請參閱this部分文檔。

+0

另外,因爲他正在創建'work',所以讓主線程自己調用'io_service :: run()',什麼都不會退出。正如所寫,當線程池超出範圍時,它會銷燬工作對象,但不會因爲主要進行運行而被銷燬。 –

+0

謝謝,完美的答案。只有確定我明白了:除了所有「真實」任務外,工作對象是一個「僞任務」。它唯一的用途是保持線程池活着? – Johannes

+0

基本上,是的。 – Chad