Как запланировать выполнение функции-члена в boost :: threadpoool - PullRequest
3 голосов
/ 26 октября 2011

Я нашел threadpool , который, кажется, еще не воодушевлен, но я могу сейчас его использовать (если нет лучшего решения).

У меня есть несколько миллионов небольших задач, которые я хочу выполнить одновременно, и я хотел использовать threadpool для планирования выполнения задач. Документация из threadpool предоставляет (примерно) этот пример:

#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.
}

Однако этот пример позволяет мне только планировать функции, не являющиеся членами (или задачи). Можно ли запланировать выполнение функции-члена?

Обновление:

ОК, предположительно, библиотека позволяет запланировать Runnable для выполнения , но я не могу понять, где находится класс 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())));
}

Однако в адаптере из библиотеки есть ошибка:

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

Обратите внимание, что для этого требуется ссылка на Pool, но он пытается вызвать его так, как если бы он был указателем на Pool, поэтому мне тоже пришлось это исправить (просто изменив -> на * 1041) *).

Ответы [ 4 ]

3 голосов
/ 26 октября 2011

Чтобы запланировать любую функцию или функцию-член - используйте Boost.Bind или Boost.Lambda (в этом порядке).Также вы можете рассмотреть специальные библиотеки для вашей ситуации.Я могу порекомендовать Inter Threading Building Blocks или, если вы используете VC2010 - Microsoft Parallel Patterns Library .

РЕДАКТИРОВАТЬ:

Я никогдаиспользовал эту библиотеку или слышал о ней что-то плохое, но она достаточно старая и до сих пор не включена в Boost.Я бы проверил почему.

РЕДАКТИРОВАТЬ 2:

Другой вариант - Boost.Asio .Это в первую очередь сетевая библиотека, но у нее есть планировщик, который вы можете использовать.Я бы использовал этот многопоточный подход .Просто вместо использования асинхронных сетевых операций планируйте свои задачи на boost::asio::io_service::post().

2 голосов
/ 28 октября 2011

Я думаю, что выяснил, что мне нужно сделать: я должен сделать 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, поэтому мне пришлось это тоже исправить (просто изменив -> на .).

Однако, как оказалось, я не могу использовать этот пул потоков поддержки, потому что я смешиваю нативный код C ++ (dll), C ++ / CLI (dll) и .NET: у меня есть библиотека C ++ / CLI, которая оборачивает нативная библиотека C ++, которая в tern использует boost :: thread. К сожалению, это приводит к BadImageFormatException во время выполнения (, который ранее обсуждался другими людьми ):

Проблема в том, что библиотека потоков статического буста пытается перехватить родные обратные вызовы TLS win32 PE для обеспечения того, чтобы поток был локальным данные, используемые бустером, корректно очищаются. Это не совместим с исполняемым файлом C ++ / CLI.

0 голосов
/ 25 июня 2016

Понял, у вас должен быть определен метод run (), это самый простой способ:

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

В main () tp - ваш пул потоков:

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

Готово.

0 голосов
/ 30 декабря 2013

Это решение я смог реализовать, используя информацию: http://think -async.com / Asio / Recipes .Я попытался реализовать этот рецепт и обнаружил, что код работает в Windows, но не в Linux.Мне не удалось выяснить проблему, но поиск в Интернете нашел ключ, который сделал рабочий объект автоматическим указателем в блоке кода.Я включил void task (), который пользователь хотел для моего примера. Я смог создать вспомогательную функцию и передать указатели в свою функцию.В моем случае я создаю пул потоков, который использует функцию: boost :: thread :: hardware_concurrency (), чтобы получить возможное количество потоков.Я использовал приведенный ниже рецепт для 80 заданий с 15 потоками.

#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();

}
...