如何在boost :: threadpool中安排成员函数的执行

时间:2011-10-25 21:39:09

标签: c++ multithreading boost threadpool

我发现threadpool似乎还没有提升,但我现在可以使用它(除非有更好的解决方案)。

我有几百万个小任务要同时执行,我想使用threadpool来安排执行任务。 threadpool的{​​{3}}提供(大致)此示例:

#include "threadpool.hpp"
using namespace boost::threadpool;

// A short task
void task()
{
    // do some work
}

void execute_with_threadpool(int poolSize, int numTasks)
{
    // Create a thread pool.
    pool tp(poolSize);

    for(int i = 0; i++; i < numTasks)
    {
        // Add some tasks to the pool.
        tp.schedule(&task);
    }
    // Leave this function and wait until all tasks are finished.
}

但是,该示例仅允许我安排非成员函数(或任务)。有没有办法可以安排成员函数执行?

更新

好吧,据说是documentation,但我无法弄清楚我应该继承的Runnable类。

template<typename Pool, typename Runnable>
bool schedule(Pool& pool, shared_ptr<Runnable> const & obj);

UPDATE2:

我想我发现了我需要做的事情:我必须创建一个runnable,它将获取任何必要的参数(包括对具有将被调用的函数的对象的引用),然后我使用静态调度函数,用于调度给定threadpool上的可运行:

class Runnable
{
private:
    MyClass* _target;
    Data* _data;
public:
    Runnable(MyClass* target, Data* data)
    {
        _target = target;
        _data = data;
    }

    ~Runnable(){}

    void run()
    {
        _target->doWork(_data);
    }
};

以下是我在MyClass中安排的方式:

void MyClass::doWork(Data* data)
{
    // do the work
}

void MyClass::produce()
{
    boost::threadpool::schedule(myThreadPool, boost::shared_ptr<Runnable>(new Runnable(myTarget, new Data())));
}

但是,library allows you to schedule a Runnable for execution中有一个错误:

template<typename Pool, typename Runnable>
bool schedule(Pool& pool, shared_ptr<Runnable> const & obj)
{ 
    return pool->schedule(bind(&Runnable::run, obj));
} 

请注意,它需要引用Pool,但它会尝试将其称为Pool的指针,因此我也必须修复它(只需更改{{1}转到->)。

4 个答案:

答案 0 :(得分:3)

要安排任何功能或成员功能 - 请使用Boost.BindBoost.Lambda(按此顺序)。您也可以根据自己的情况考虑使用特殊库。我可以推荐Inter Threading Building Blocks,或者如果你使用VC2010,我可以推荐Microsoft Parallel Patterns Library

编辑:

我从来没有使用过这个库,也没有听过任何关于它的坏消息,但是它已经足够老了,仍然没有包含在Boost中。我会检查原因。

编辑2:

另一种选择 - Boost.Asio。它主要是一个网络库,但它有一个可以使用的调度程序。我会用this multithreading approach。而不是使用异步网络操作而是按boost::asio::io_service::post()计划任务。

答案 1 :(得分:2)

我想我发现了我需要做的事情:我必须创建一个runnable,它将获取任何必要的参数(包括对具有将被调用的函数的对象的引用),然后我使用静态调度函数,用于调度给定threadpool上的可运行:

class Runnable
{
private:
    MyClass* _target;
    Data* _data;
public:
    Runnable(MyClass* target, Data* data)
    {
        _target = target;
        _data = data;
    }

    ~Runnable(){}

    void run()
    {
        _target->doWork(_data);
    }
};

以下是我在MyClass中安排的方式:

void MyClass::doWork(Data* data)
{
    // do the work
}

void MyClass::produce()
{
    boost::threadpool::schedule(myThreadPool, boost::shared_ptr<Runnable>(new Runnable(myTarget, new Data())));
}

但是,库中的适配器中有一个错误:

template<typename Pool, typename Runnable>
bool schedule(Pool& pool, shared_ptr<Runnable> const & obj)
{ 
    return pool->schedule(bind(&Runnable::run, obj));
} 

请注意,它需要引用Pool,但它会尝试将其称为Pool的指针,因此我也必须修复它(只需更改{{1}转到->)。

然而,事实证明,我不能使用那个提升线程池,因为我正在混合本机C ++(dll),C ++ / CLI(dll)和.NET代码:我有一个C ++ / CLI库包装本机C ++库,它使用boost :: thread。不幸的是,这会在运行时产生.which has previously been discussed by other people):

  

问题是静态提升线程库试图挂钩   本机win32 PE TLS回调以确保线程本地   boost线程使用的数据被正确清理。这不是   与C ++ / CLI可执行文件兼容。

答案 2 :(得分:0)

此解决方案是我能够使用以下信息实现的:http://think-async.com/Asio/Recipes。我尝试实现这个配方,发现代码在Windows中有效但在Linux中没有。我无法弄清楚问题,但搜索互联网时发现了一个键,它使工作对象成为代码块中的自动指针。我已经为我的示例包含了用户想要的void task()我能够创建一个便利函数并将指针传递给我的函数来完成工作。对于我的情况,我创建了一个使用函数的线程池:boost :: thread :: hardware_concurrency()来获取可能的线程数。我已经使用了下面的配方,包含15个线程的多达80个任务。

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

// A short task
void task()
{
    // do some work
}

void execute_with_threadpool( int numTasks, 
                              int poolSize = boost::thread::hardware_concurrency() )
{
    boost::asio::io_service io_service;
    boost::thread_group threads;
    {
        boost::scoped_ptr< boost::asio::io_service::work > work( new boost::asio::io_service::work(io_service) );

        for(int t = 0; t < poolSize; t++)
        {
            threads.create_thread(boost::bind(&boost::asio::io_service::run, &io_service));
        }

        for( size_t t = 0; t < numTasks; t++ )
        {
            ++_number_of_jobs;
            io_service.post(boost::bind(task) );
        }
    }
    threads.join_all();

}

答案 3 :(得分:0)

想出来,你必须定义run()方法,这是最简单的方法:

class Command
{
public:
    Command()  {}
    ~Command() {}
    void run() {}
};

在main()中,tp是你的线程池:

shared_ptr<Command> pc(new Command());
tp.schedule(bind(&Command::run, pc));

完成。