Небольшая библиотечка, предоставляющая возможность асинхронного выполнения задач.
Навеяно идеями Kevlin Henney (
http://www.two-sdg.demon.co.uk/curbralan/papers/accu/MoreC++Threading.pdf,
http://www.two-sdg.demon.co.uk/curbralan/papers.html).
В boost sandbox'е есть уже что-то подобное (я тут немного припоздал
). Но у них жесткая привязка к boost::thread, тогда как у меня это можно конфигурировать с помощью executor'ов. Пока что реализовано три вида executor'ов: instant_executor — сразу выполняет задачу в текущем потоке, thread_executor — в отдельном потоке, созданном с помощью boost::thread, atl_thread_pool_executor — в ATL пуле.
Реализована поддержка исключений (так же нет в boost'овском варианте). Исключение, выбрасываемое в отдельном потоке, перебрасывается в текущем потоке при попытке узнать результат исполнения задачи.
Естественно, это всё работает с лямбдами и boost::function за милую душу.
Платформа: Win32.
Зависимости: boost, ATL
Файл здесь:
http://rsdn.ru/File/15955/futures_redist.zip
Пример:
int foo() { // some function }
void bar() {}
void throwing_bar() { // throw my_exception derived from rethrowable_error }
thread_executor exec;
future<int> foo_joiner = exec(foo); // queue execution
int result = foo_joiner(); // get the result
atl_thread_pool_executor atlexec(2); // number of threads = 2
future<> bar_joiner = altexec(bar);
if (bar_joiner) // finished yet?
{
}
bar_joiner(); // wait for completion
try
{
future<> throwing_joiner = altexec(throwing_bar); // execute thrower in a separate thread
throwing_joiner(); // exception is rethrown here!
}
catch (my_exception &)
{
// the exception has the correct type
}
Здравствуйте, alexeiz, Вы писали:
A>Небольшая библиотечка, предоставляющая возможность асинхронного выполнения задач.
Достаточно неплохо. Но хотелось бы:
— Независимости. То есть, чтобы эта штука работала на любом пуле потоков. Причем, свойства пула должны быть (а)достаточно просты для самостоятельно реализации такого пула (б)строго документированы
Например так:
future<int> f1 = exec(foo, thread_pool1);//будет выполняться в пуле потоков №1
future<int> f2 = exec(foo, thread_pool2);//будет выполняться в пуле потоков №2
— Чтобы на обьекте future<> можно было "ожидать". Как с таймаутом, так и без. И, очень желательно, без "busy waiting".
future<int> f1 = exec(foo);
....
if( f1.wait(1000) /*ждем секунду*/ )
{
std::cout << f1.get() << std::endl;
} else {
std::cout << "Не дождались" << std::endl;
}
Здравствуйте, 0xDEADBEEF, Вы писали:
DEA>Здравствуйте, alexeiz, Вы писали:
A>>Небольшая библиотечка, предоставляющая возможность асинхронного выполнения задач.
DEA>Достаточно неплохо. Но хотелось бы:
DEA>- Независимости. То есть, чтобы эта штука работала на любом пуле потоков. Причем, свойства пула должны быть (а)достаточно просты для самостоятельно реализации такого пула (б)строго документированы
DEA>Например так:
DEA>DEA>future<int> f1 = exec(foo, thread_pool1);//будет выполняться в пуле потоков №1
DEA>future<int> f2 = exec(foo, thread_pool2);//будет выполняться в пуле потоков №2
DEA>
Так элементарно же:
atl_thread_pool_executor pool1;
atl_thread_pool_executor pool2;
future<int> f1 = pool1(foo);
future<int> f2 = pool2(foo);
Сами пулы реализовывать несложно. Вся вспомогательная функциональность уже есть. А конкретный executor — это просто надстройка. Если посмотреть файл atl_thread_pool_executor.hpp, там буквально два класса, по одной функции в каждом. Я на досуге собираюсь еще и win32 пул сделать.
DEA>- Чтобы на обьекте future<> можно было "ожидать". Как с таймаутом, так и без. И, очень желательно, без "busy waiting".
DEA>DEA>future<int> f1 = exec(foo);
DEA>....
DEA>if( f1.wait(1000) /*ждем секунду*/ )
DEA>{
DEA> std::cout << f1.get() << std::endl;
DEA>} else {
DEA> std::cout << "Не дождались" << std::endl;
DEA>}
DEA>
Просто ожидать можно. Эта функциональность объеденена с запросом результата. Т.е.:
int result = f1(); // wait for completion and get the result
С таймаутом пока нельзя. Но скоро будет. Думаю сделать интерфейс ввиде логических операций. На данный момент уже возможно такое:
if (f1) // non-blocking check for comletion (e.g. try_wait)
{ ... }
С таймаутом будет так:
if (f1 || timeout(1000)) // whatever happens first, f1 completes or timeout
{ ... }
if (f1 || f2 || timeout(1000)) // first of the three
{ ... }
if (f1 && f2 || timeout(1000)) // f1 *and* f2 should both complete or timeout
{ ... }
Пофиксил баг связанный с живучестью асинхронного объекта. Сделал atl_thread_pool_executor copy-constructible.
http://rsdn.ru/File/15955/futures_redist.zip