Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

when_any, produce first outcome, whether result or exception

Boost , Chapter 1. Fiber , when_any

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Мы не можем работать в среде, в которой мы можем гарантировать, что ни одна из наших задач не будет выполнена. В этом случае вышеприведенные реализации<wait_first_something()>были бы naïve: как упоминалось вразделе «Управление волокнами», непойманное исключение в одном из наших волокон задачи вызвало бы вызов<std::terminate()>.

Давайте хотя бы позаботимся о том, чтобы такое исключение распространилось на волокно, ожидающее первого результата. Мы можем использовать<future<>>для перевозки либо возвратного значения, либо исключения. Мы изменим.<wait_first_value()><unbounded_channel<>>держать<future< T>>предметов вместо просто<T>.

Как только у нас есть<future<>>в руке, все, что нам нужно сделать, это позвонить<future::get()>, который либо вернет значение, либо отбросит исключение.

template< typename Fn, typename ... Fns >
typename std::result_of< Fn() >::type
wait_first_outcome( Fn && function, Fns && ... functions) {
    // In this case, the value we pass through the channel is actually a
    // future -- which is already ready. future can carry either a value or an
    // exception.
    typedef typename std::result_of< Fn() >::type return_t;
    typedef boost::fibers::future< return_t > future_t;
    typedef boost::fibers::unbounded_channel< future_t > channel_t;
    auto channelp(std::make_shared< channel_t >() );
    // launch all the relevant fibers
    wait_first_outcome_impl< return_t >( channelp,
                                         std::forward< Fn >( function),
                                         std::forward< Fns >( functions) ... );
    // retrieve the first future
    future_t future( channelp->value_pop() );
    // close the channel: no subsequent push() has to succeed
    channelp->close();
    // either return value or throw exception
    return future.get();
}

До сих пор так хорошо и #8212, но есть проблема с временем. Как нам получить<future<>>до<unbounded_channel::push()>на канале?

Мы могли бы позвонить<fibers::async()>. Это, безусловно, приведет к<future<>>задаче. Проблема в том, что он вернется слишком быстро! Мы хотим, чтобы<future<>>пунктовзавершилизадачи на нашем<unbounded_channel<>>. Мы желаем только того, кто будет первым.<future<>>Если бы каждое волокно, запущенное<wait_first_outcome()>, было<push()>результатом вызова<async()>, канал только сообщал бы результат самого левого пункта задачи —нетот, который завершается наиболее быстро.

Призыв<future::get()>на будущее, возвращенное<async()>, был бы неправильным. Вы можете позвонить<get()>только один раз<future<>>. И если бы было исключение, оно было бы переброшено внутрь волокна-помощника на конце канала производителя, а не размножено на конце потребителя.

Мы могли бы позвонить<future::wait()>. Это будет блокировать волокна помощника, пока<future<>>не станет готовым, и в этот момент мы можем<push()>его получить<wait_first_outcome()>.

Это сработает #8212, но есть более простая тактика, которая позволяет избежать создания дополнительного волокна. Мы можем обернуть функцию задачи в<packaged_task<>>. В то время как кто-то, естественно, думает о том, чтобы передать<packaged_task<>>новому волокну — то есть, на самом деле, то, что делает<async()>— в этом случае мы уже запускаем вспомогательное волокно в конце канала производителя! Мы можем простоназвать<packaged_task<>>. По возвращении с этого вызова функция задачи завершена, что означает, что<future<>>, полученный от<packaged_task<>>, наверняка будет готов. В этот момент мы можем просто<push()>перейти на канал.

template< typename T, typename CHANNELP, typename Fn >
void wait_first_outcome_impl( CHANNELP channel, Fn && function) {
    boost::fibers::fiber(
        // Use std::bind() here for C++11 compatibility. C++11 lambda capture
        // can't move a move-only Fn type, but bind() can. Let bind() move the
        // channel pointer and the function into the bound object, passing
        // references into the lambda.
        std::bind(
            []( CHANNELP & channel,
                typename std::decay< Fn >::type & function) {
                // Instantiate a packaged_task to capture any exception thrown by
                // function.
                boost::fibers::packaged_task< T() > task( function);
                // Immediately run this packaged_task on same fiber. We want
                // function() to have completed BEFORE we push the future.
                task();
                // Pass the corresponding future to consumer. Ignore
                // channel_op_status returned by push(): might be closed; we
                // simply don't care.
                channel->push( task.get_future() );
            },
            channel,
            std::forward< Fn >( function)
        )).detach();
}

Называть это может выглядеть так:

std::string result = wait_first_outcome(
        [](){ return sleeper("wfos_first",   50); },
        [](){ return sleeper("wfos_second", 100); },
        [](){ return sleeper("wfos_third",  150); });
std::cout << "wait_first_outcome(success) => " << result << std::endl;
assert(result == "wfos_first");
std::string thrown;
try {
    result = wait_first_outcome(
            [](){ return sleeper("wfof_first",   50, true); },
            [](){ return sleeper("wfof_second", 100); },
            [](){ return sleeper("wfof_third",  150); });
} catch ( std::exception const& e) {
    thrown = e.what();
}
std::cout << "wait_first_outcome(fail) threw '" << thrown
          << "'" << std::endl;
assert(thrown == "wfof_first");


PrevUpHomeNext

Статья when_any, produce first outcome, whether result or exception раздела Chapter 1. Fiber when_any может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: when_any ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-07-05 07:40:41/0.0045371055603027/0