如何在 C++ 中使用 boost 创建线程池?

Posted

技术标签:

【中文标题】如何在 C++ 中使用 boost 创建线程池?【英文标题】:How to create a thread pool using boost in C++? 【发布时间】:2013-10-30 07:01:08 【问题描述】:

如何在 C++ 中使用 boost 创建线程池,以及如何将任务分配给线程池?

【问题讨论】:

唯一的问题是它不允许我回答其他问题,并且允许并鼓励自我回答。 你应该可以回复the other question,它没有关闭或protected。 我已经发布了,但被工作人员删除了。 @SamMiller 为什么会被删除?对我来说似乎有效。如果您将其重新发布到原始问题,我会支持您。 【参考方案1】:

这个过程非常简单。首先创建一个 asio::io_service 和一个 thread_group。用链接到 io_service 的线程填充 thread_group。使用boost::bind 函数将任务分配给线程。

要停止线程(通常在您退出程序时),只需停止 io_service 并加入所有线程。

您应该只需要这些标题:

#include <boost/asio/io_service.hpp>
#include <boost/bind.hpp>
#include <boost/thread/thread.hpp>

这是一个例子:

/*
 * Create an asio::io_service and a thread_group (through pool in essence)
 */
boost::asio::io_service ioservice;
boost::thread_group threadpool;


/*
 * This will start the ioService processing loop. All tasks 
 * assigned with ioService.post() will start executing. 
 */
boost::asio::io_service::work work(ioService);

/*
 * This will add 2 threads to the thread pool. (You could just put it in a for loop)
 */
threadpool.create_thread(
    boost::bind(&boost::asio::io_service::run, &ioService)
);
threadpool.create_thread(
    boost::bind(&boost::asio::io_service::run, &ioService)
);

/*
 * This will assign tasks to the thread pool. 
 * More about boost::bind: "http://www.boost.org/doc/libs/1_54_0/libs/bind/bind.html#with_functions"
 */
ioService.post(boost::bind(myTask, "Hello World!"));
ioService.post(boost::bind(clearCache, "./cache"));
ioService.post(boost::bind(getSocialUpdates, "twitter,gmail,facebook,tumblr,reddit"));

/*
 * This will stop the ioService processing loop. Any tasks
 * you add behind this point will not execute.
*/
ioService.stop();

/*
 * Will wait till all the threads in the thread pool are finished with 
 * their assigned tasks and 'join' them. Just assume the threads inside
 * the threadpool will be destroyed by this method.
 */
threadpool.join_all();

来源:Recipes < Asio

【讨论】:

boost::asio::io_service::work 对象是使其正常运行的关键部分。此外,io_service::stop() 将阻止执行任何其他任务,无论该任务何时发布到 io_service。例如,虽然getSocialUpdates()stop() 之前添加到io_service 队列中,但如果在调用stop() 时它不是在执行中,那么它将保持在队列中。 @TannerSansbury 实际上这个食谱让我很困惑,因为在 io_service.stop() 之后我所有未完成的工作都被杀死了。正确的方法应该是删除 ioservice.stop() 但破坏工作对象,然后调用 threadpool.join_all() 让所有工作完成。 请参阅"Stopping the io_service from running out of work" in the io_service documentation,了解io_service::stop()(丢弃排队的工作)与销毁work 对象(耗尽排队的工作)之间的区别。 如果我使用这个配方,并不是所有的任务都必须处理。从某种意义上说,某些功能(发布的任务)没有被调用。但是,如果我将任务的发布移到线程池对象的创建之上,摆脱工作并更改连接和停止操作的顺序,一切都会完美无缺。这是正常的吗?我是不是错过了什么。我正在使用 boost 1.54。【参考方案2】:

从 boost 1.66.0 开始,有一个thread_pool 类:

#include <boost/asio/thread_pool.hpp>
#include <boost/asio/post.hpp>

boost::asio::thread_pool pool(4); // 4 threads
boost::asio::post(pool, [] );
pool.join();

请参阅description。

【讨论】:

很高兴看到现代、最新的解决方案。【参考方案3】:

我知道你喜欢代码。

我的版本

namespace bamthread

    typedef std::unique_ptr<boost::asio::io_service::work> asio_worker;

    struct ThreadPool 
        ThreadPool(size_t threads) :service(), working(new asio_worker::element_type(service)) 
            while(threads--)
            
                auto worker = boost::bind(&boost::asio::io_service::run, &(this->service));
                g.add_thread(new boost::thread(worker));
            
        

        template<class F>
            void enqueue(F f)
                service.post(f);
            

        ~ThreadPool() 
            working.reset(); //allow run() to exit
            g.join_all();
            service.stop();
        

        private:
        boost::asio::io_service service; //< the io_service we are wrapping
        asio_worker working;
        boost::thread_group g; //< need to keep track of threads so we can join them
    ;

使用它的一段代码:


    bamthread::ThreadPool tp(n_threads);
    BOOST_FOREACH(int y, boost::irange(starty, endy, step))
        int im_x = 0;
        BOOST_FOREACH(int x, boost::irange(startx, endx, step))
            tp.enqueue (boost::bind(&camera_view_depth::threaded_intersection, this,
                        intersections, 
                        intersected,
                        im_x,
                        im_y,
                        _faces, x, y));
            ++im_x;
        
        ++im_y;
    

【讨论】:

对不起,我只想问一下,你怎么知道提问者喜欢代码? @x29a 你怎么知道我不知道提问者喜欢代码? 你如何从我的评论中得知我知道你不知道提问者是否喜欢代码? @x29a 和 squid :注意无限递归。它会很快溢出***的堆栈! 拜托!溢出***的堆栈!!

以上是关于如何在 C++ 中使用 boost 创建线程池?的主要内容,如果未能解决你的问题,请参考以下文章

C++ boost::asio::io_service创建线程池thread_group简单实例

C++ boost::asio::io_service创建线程池thread_group简单实例

使用 boost::asio::thread_pool 的 C++ 线程池,为啥我不能重用我的线程?

C ++线程池[关闭]

使用 boost 创建线程池

使用boost asio的线程池