Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > async+future+уведомление


Автор: borisbn 26.2.2012, 09:42
Здравствуйте.

Нет ли стандартного способа вызвать функцию по окончании работы функции, переданной в async? Желательно, чтобы в функцию-уведомление передалось бы в качестве параметра возвращаемое значение функции из async.

Спасибо. 

Автор: boostcoder 26.2.2012, 09:55
стандартного - нет.
но можно передать свой функциональный объект с operator(), который будет вызывать связанную с ним функцию-уведомитель по завершению функции-задачи.


Автор: boostcoder 26.2.2012, 10:20
хотя...вроде бы есть такая возможность, путем использования packaged_task::make_ready_at_thread_exit()
но проблема в том, что make_ready_at_thread_exit() еще не реализован. даже декларации нет. smile 
но в доках он присутствует: http://www.stdthread.co.uk/doc/headers/future/packaged_task/make_ready_at_thread_exit.html и http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3070.html.

Автор: borisbn 27.2.2012, 14:52
Я тут повелосипедировал немного... Глянешь на досуге ? Покритикуешь ?
Код

namespace Async {

template< class Res >
void async_p( std::function< Res() > worker, std::function< void(Res) > waiter
            , typename std::enable_if< ! std::is_void< Res >::value >::type * p = 0 )
{
    waiter( worker() );
}

template< class Res >
void async_p( std::function< void() > worker, std::function< void() > waiter
            , typename std::enable_if< std::is_void< Res >::value >::type * p = 0 )
{
    worker();
    waiter();
}

template< class Waiter, class ... Args >
std::future< void > run( Waiter bound_waiter, Args ... args )
{
    typedef decltype( std::bind( args... )() ) Worker_Res;
    std::function< Worker_Res() > worker = std::bind( args... );
    return std::async( async_p< Worker_Res >, worker, bound_waiter, nullptr );
}

template< class Worker_Res, class Waiter, class ... Args >
std::future< void > run( void (Waiter::*waiter_f)(Worker_Res), Waiter waiter, Args ... args )
{
    std::function< Worker_Res() > worker = std::bind( args... );
    std::function< void(Worker_Res) > bound_waiter =
        std::bind( waiter_f, waiter, std::placeholders::_1 );
    return run( bound_waiter, args... );
}

template< class Waiter, class ... Args >
std::future< void > run( void (Waiter::*waiter_f)(), Waiter waiter, Args ... args )
{
    std::function< void() > worker = std::bind( args... );
    std::function< void() > bound_waiter = std::bind( waiter_f, waiter );
    return run( bound_waiter, args... );
}

} // namespace Async {

using std::cout;
using std::endl;

class Worker {
public:
    std::string work( const std::string & str, int x ) {
        cout << "Worker::work( " << str << ", " << x << " );" << endl;
        return str;
    }
};

class Waiter {
public:
    void onFinish( const std::string & str ) {
        cout << "Waiter::onFinish( " << str << " );" << endl;
    }
    void onFinish_v() {
        cout << "Waiter::onFinish( void );" << endl;
    }
};

void onFinish( const std::string & str ) {
    cout << "::onFinish( " << str << " );" << endl;
}

void work() {
    cout << "__work__( " << endl;
}

void onFinish_v() {
    cout << "::onFinish( void  );" << endl;
}


Worker worker;
Waiter waiter;

int main()
{
    auto f_v = Async::run( &Waiter::onFinish_v, waiter, work );
    auto f_x = Async::run( onFinish_v, work );
    auto f_0 = Async::run( onFinish, &Worker::work, worker, "str for worker 0", 42 );
    auto f_1 = Async::run( &Waiter::onFinish, waiter, &Worker::work, worker, "str for worker 1", 421 );
   
    f_1.wait();
    f_0.wait();
    f_x.wait();
    f_v.wait();
}

http://liveworkspace.org/code/5f5fc2a2f050ee0d953d8d49fddc85b9

Автор: boostcoder 28.2.2012, 14:33
borisbn, так а цель была, уйти от явного использования bind() ?

Автор: borisbn 28.2.2012, 14:41
Цитата(boostcoder @  28.2.2012,  14:33 Найти цитируемый пост)
цель была, уйти от явного использования bind() ? 

Ага. В том числе. Хочу, чтобы мои функции выглядели для пользователя как тот же std::thread или std::async...
К тому же если рабочая функция возвращает значение, то функции-уведомлению нужно делать std::bind с placeholder'ом, а если нет - то без него. А так получается единообразно.

Ну, а основная цель - сделать async-вызов с уведомлением. В принципе, я её достиг, но меня смущает то, что пользователь должен получать std::future и в конце программы (например, в деструкторе основного класса) ожидать её. Хотелось бы и этот процесс автоматизировать, но я пока не придумал как. Есть идея создать статический глобальный класс, который будет получать эти future'зы, складывать в список, а в своём деструкторе - ждать всех по-очереди... Бррр... самому не нравится

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)