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

when_any, produce first success

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

Один из сценариев для функциональных возможностей , когда_any - это когда мы излишне связываемся с некоторым количеством потенциально ненадежных веб-сервисов. Мало того, что они могут быть медленными, любой из них может привести к неудаче, а не к желаемому результату.

В таком случае wait_first_outcome() не является правильным подходом. Если одна из служб быстро допускает ошибку, а другая дает реальный ответ, мы не хотим отдавать предпочтение ошибке только потому, что она появилась первой!

Учитывая unbounded_channel< T > > > мы уже создали для wait_first_outcome(), хотя мы можем легко переделать функцию интерфейса, чтобы получить первый успешный результат.

Возникает вопрос: что, если все функции задачи бросают исключение? В таком случае нам, наверное, лучше об этом знать.

Проект технического задания на параллелизм C++ предлагает исключение std:: Exception_list, способное предоставить коллекцию std:: Exception_ptrs. Пока это не станет общедоступным, давайте подделаем собственный список исключений :

class exception_list : public std::runtime_error {
public:
    exception_list( std::string const& what) :
        std::runtime_error( what) {
    }
    typedef std::vector< std::exception_ptr >   bundle_t;
    // N4407 proposed std::exception_list API
    typedef bundle_t::const_iterator iterator;
    std::size_t size() const noexcept {
        return bundle_.size();
    }
    iterator begin() const noexcept {
        return bundle_.begin();
    }
    iterator end() const noexcept {
        return bundle_.end();
    }
    // extension to populate
    void add( std::exception_ptr ep) {
        bundle_.push_back( ep);
    }
private:
    bundle_t bundle_;
};

Теперь мы можем построить wait_first_success(), используя wait_first_outcome_impl().

unbounded_channel::pop() call навсегда. .unbounded_channel::pop() call would block forever. [ORIG_END] -->

При наличии готового future<>, можно отличить отказ, позвонив future::get_ Exception_ptr(). Если будущее<> на самом деле содержит результат, а не исключение, get_ Exception_ptr() возвращает nullptr. В этом случае мы можем уверенно позвонить будущее::get(), чтобы вернуть результат нашему абоненту.

nullptr, однако, мы собираем exception_listfuture<> от канала. .

Если мы выпадаем из цикла — если каждое отдельное волокно задачи бросает исключение — мы бросаем исключение Исключение_список , в который мы собрали те std:: Исключение_ptr.

template< typename Fn, typename ... Fns >
typename std::result_of< Fn() >::type
wait_first_success( Fn && function, Fns && ... functions) {
    std::size_t count( 1 + sizeof ... ( 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< typename std::decay< Fn >::type() >::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) ... );
    // instantiate exception_list, just in case
    exception_list exceptions("wait_first_success() produced only errors");
    // retrieve up to 'count' results -- but stop there!
    for ( std::size_t i = 0; i < count; ++i) {
        // retrieve the next future
        future_t future( channelp->value_pop() );
        // retrieve exception_ptr if any
        std::exception_ptr error( future.get_exception_ptr() );
        // if no error, then yay, return value
        if ( ! error) {
            // close the channel: no subsequent push() has to succeed
            channelp->close();
            // show caller the value we got
            return future.get();
        }
        // error is non-null: collect
        exceptions.add( error);
    }
    // We only arrive here when every passed function threw an exception.
    // Throw our collection to inform caller.
    throw exceptions;
}

Звонок может выглядеть так:

std::string result = wait_first_success(
            [](){ return sleeper("wfss_first",   50, true); },
            [](){ return sleeper("wfss_second", 100); },
            [](){ return sleeper("wfss_third",  150); });
std::cout << "wait_first_success(success) => " << result << std::endl;
assert(result == "wfss_second");


PrevUpHomeNext

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




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



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


реклама


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

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 21:35:38/0.010087966918945/1