![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
Symmetric coroutineBoost , Chapter 1. Coroutine , Coroutine
|
![]() |
Important |
---|---|
симметричный_coroutine<>::yield_typeможет быть создано только в рамках. |
std::vector<int> merge(const std::vector<int>& a,const std::vector<int>& b) { std::vector<int> c; std::size_t idx_a=0,idx_b=0; boost::coroutines::symmetric_coroutine<void>::call_type* other_a=0,* other_b=0; boost::coroutines::symmetric_coroutine<void>::call_type coro_a( [&](boost::coroutines::symmetric_coroutine<void>::yield_type& yield) { while(idx_a<a.size()) { if(b[idx_b]<a[idx_a]) // test if element in array b is less than in array a yield(*other_b); // yield to coroutine coro_b c.push_back(a[idx_a++]); // add element to final array } // add remaining elements of array b while ( idx_b < b.size()) c.push_back( b[idx_b++]); }); boost::coroutines::symmetric_coroutine<void>::call_type coro_b( [&](boost::coroutines::symmetric_coroutine<void>::yield_type& yield) { while(idx_b<b.size()) { if (a[idx_a]<b[idx_b]) // test if element in array a is less than in array b yield(*other_a); // yield to coroutine coro_a c.push_back(b[idx_b++]); // add element to final array } // add remaining elements of array a while ( idx_a < a.size()) c.push_back( a[idx_a++]); }); other_a = & coro_a; other_b = & coro_b; coro_a(); // enter coroutine-fn of coro_a return c; } std::vector< int > a = {1,5,6,10}; std::vector< int > b = {2,4,7,8,9,13}; std::vector< int > c = merge(a,b); print(a); print(b); print(c); output: a : 1 5 6 10 b : 2 4 7 8 9 13 c : 1 2 4 5 6 7 8 9 10 13
В этом примере дваsymmetric_coroutine<>::call_typeсоздаются в контексте основного исполнения, принимая функцию лямбда (==coroutine-function), которая объединяет элементы двух сортированных массивов в третий массив.<coro_a()
>входит вкорутин-функцию<coro_a
>цикла через массив и тестирование, если фактический элемент в другом массиве меньше, чем элемент в локальном. Если это так, то корутин уступает другому корутину<coro_b
>, используя<yield(*other_b)
>. Если текущий элемент локального массива меньше, чем элемент другого массива, он помещается в третий массив. Поскольку корутин возвращается к<coro_a()
>(возвращается из этого метода) после выхода изкорутинной функции, элементы другого массива будут добавлены в конце третьего массива, если весь элемент локального массива будет обработан.
корутинная функциявозвращаетпустотуи принимаетсимметрию_coroutine<>::yield_type, обеспечивая корутинную функциональность внутрикорутинной функции, в качестве аргумента. Использование этого экземпляра является единственным способом передачи данных и управления исполнением.symmetric_coroutine<>::call_typeне входит вкорутин-функциюприsymmetric_coroutine<>::call_typeконструкция, но при первом вызовеsymmetric_coroutine<>::call_type::operator().
Если параметр шаблона не является<void
>,изсимметричного_coroutine<>::call_typeможет предположить, что (a) при первоначальном вводе и (b) после каждогосимметричного_coroutine<>::yield_type::operator()вызова, егосимметричного_coroutine<>::yield_type:::get().имеет новое доступное значение.
Однако, если параметр шаблона является типом только для перемещения,symmetric_coroutine<>::yield_type::get()может называться только один раз перед следующимsymmetric_coroutine<>::yield_type::operator()призыв.
Для передачи данных вsymmetric_coroutine<>::call_typeиз основного контекста фреймворк синтезируетsymmetric_coroutine<>::yield_typeсвязан сsymmetric_coroutine<>::call_typeэкземпляром. Синтезированныйsymmetric_coroutine<>::yield_typeпередается как аргумент.корутинная функция. Основной контекст должен называтьсяsymmetric_coroutine<>::call_type::operator().для передачи каждого значения данных вкорутинная функция. Доступ к передаваемому значению данных даетsymmetric_coroutine<>::yield_type::get().
boost::coroutines::symmetric_coroutine<int>::call_type coro( // constructor does NOT enter coroutine-function [&](boost::coroutines::symmetric_coroutine<int>::yield_type& yield){ for (;;) { std::cout << yield.get() << " "; yield(); // jump back to starting context } }); coro(1); // transfer {1} to coroutine-function coro(2); // transfer {2} to coroutine-function coro(3); // transfer {3} to coroutine-function coro(4); // transfer {4} to coroutine-function coro(5); // transfer {5} to coroutine-function
Непойманное исключение внутриsymmetric_coroutine<>::call_type'scoroutine-functionвызоветstd::terminate().
![]() |
Important |
---|---|
Код, выполняемый корутиной, не должен препятствовать распространению детали::forced_unwind. Поглощение этого исключения приведет к провалу стека. Таким образом, любой код, который улавливает все исключения, должен повторно бросить любую ожидающуюдеталь::forced_unwindисключение. |
try { // code that might throw } catch(const boost::coroutines::detail::forced_unwind&) { throw; } catch(...) { // possibly not re-throw pending exception }
![]() |
Important |
---|---|
Не прыгайте изнутри блок-уловки, а затем снова бросайте исключение в другой контекст исполнения. |
Иногда необходимо раскрутить стек незавершенного корутина, чтобы уничтожить локальные переменные стека, чтобы они могли высвобождать выделенные ресурсы (паттерн RAII). Аргумент<attributes
>корутинного конструктора указывает, должен ли деструктор разматывать стек (стек разматывается по умолчанию).
Stack unwinding предполагает следующие предварительные условия:
После раскручиваниякорутиназавершена.
struct X { X(){ std::cout<<"X()"<<std::endl; } ~X(){ std::cout<<"~X()"<<std::endl; } }; boost::coroutines::symmetric_coroutine<int>::call_type other_coro(...); { boost::coroutines::symmetric_coroutine<void>::call_type coro( [&](boost::coroutines::symmetric_coroutine<void>::yield_type& yield){ X x; std::cout<<"fn()"<<std::endl; // transfer execution control to other coroutine yield( other_coro, 7); }); coro(); std::cout<<"coro is complete: "<<std::boolalpha<<!coro<<"\n"; } output: X() fn() coro is complete: false ~X()
корутин-функциявыводится с простым ответным утверждением. Это возвращает нас к вызовуsymmetric_coroutine<>::call_type::operator()в начале симметричной корутинной цепи. То есть симметричные корутины не имеют сильного, фиксированного отношения к вызывающему, как и асимметричные корутины.symmetric_coroutine<>::call_typeстановится полным, напримерsymmetric_coroutine<>::call_type::operator boolвернется<false
>.
![]() |
Important |
---|---|
После возвращения изкорутинной функциикорутинаявляется полным (не может быть возобновлено сsymmetric_coroutine<>::call_type::operator(). |
Статья Symmetric coroutine раздела Chapter 1. Coroutine Coroutine может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
реклама |