使用Boost线程和io_service创建线程池

时间:2014-03-19 03:06:38

标签: c++ boost boost-asio threadpool boost-thread

我已经浏览了Stack Overflow并且已经有了一些非常好的答案,(我的代码实际上基于this answer here)但是由于某种原因我得到了奇怪的行为 - 因为应该调用thread_func ls1次,但它只在线程退出之前运行0到2次。看起来ioService.stop()在完成排队的作业之前会切断排队的作业,但据我所知,这不应该发生。以下是相关的代码段:

boost::asio::io_service ioService;
boost::asio::io_service::work work(ioService);

boost::thread_group threadpool;

for (unsigned t = 0; t < num_threads; t++)
{   
    threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &ioService));
}   

//Iterate over the dimensions of the matrices
for (unsigned i = 0; i < ls1; i++)
{   
    ioService.post(boost::bind(&thread_func,i, rs1, rs2, ls2, arr, left_arr, &result));
}   

ioService.stop();
threadpool.join_all();

非常感谢任何帮助,谢谢!

2 个答案:

答案 0 :(得分:5)

io_service::stop() 会导致run()run_one()的所有调用尽快返回。它不会删除已排队到io_service的任何未完成的处理程序。调用io_service::stop()时,threadpool中的线程将尽快返回,从而导致每个执行线程完成。

由于io_service::post()将在请求io_service调用处理程序后立即返回,因此threadpoolio_service之前的线程将调用多少个已发布的处理程序是不确定的。 {1}}已停止。

如果您希望thread_func被调用ls1次,那么一个简单的替代方法是重新组织代码,以便在io_service之前将工作添加到threadpool为它提供服务,然后应用程序让io_service运行完成。

boost::asio::io_service ioService;

// Add work to ioService.
for (unsigned i = 0; i < ls1; i++)
{   
  ioService.post(boost::bind(
      &thread_func,i, rs1, rs2, ls2, arr, left_arr, &result));
}   

// Now that the ioService has work, use a pool of threads to service it.
boost::thread_group threadpool;    
for (unsigned t = 0; t < num_threads; t++)
{   
  threadpool.create_thread(boost::bind(
      &boost::asio::io_service::run, &ioService));
}   

// Once all work has been completed (thread_func invoked ls1 times), the
// threads in the threadpool will be completed and can be joined.
threadpool.join_all();

答案 1 :(得分:1)

如果您希望thread_func被调用ls1次,那么您应该等到实际调用ls1次,然后再停止io_service。如上所述,在任何线程都有机会被安排之前,可以调用stop()

有很多方法可以等待这种情况。例如,您可以使用条件变量:

#include <boost/asio.hpp>
#include <boost/thread.hpp>
unsigned num_threads = 10, ls1=11;
int result = 0;
boost::mutex m;
boost::condition_variable cv;
void thread_func(unsigned , int* result) {
    /* do stuff */
    {
        boost::lock_guard<boost::mutex> lk(m);
        ++*result;
    }
    cv.notify_one();
}
int main()
{
    boost::asio::io_service ioService;
    boost::asio::io_service::work work(ioService);
    boost::thread_group threadpool;
    for (unsigned t = 0; t < num_threads; t++)
        threadpool.create_thread(boost::bind(&boost::asio::io_service::run,
                                             &ioService));
    for (unsigned i = 0; i < ls1; i++)
        ioService.post(boost::bind(&thread_func,i,&result));

    {
        boost::unique_lock<boost::mutex> lk(m);
        cv.wait(lk, []{return result == ls1; });
    }
    ioService.stop();
    threadpool.join_all();
    std::cout << "result = " << result << '\n';
}