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

Symmetric coroutine

Boost , Chapter 1. Coroutine , Coroutine

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

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

symmetric_coroutine<>::call_type

symmetric_coroutine<>::call_typeзапускает симметричный корутин и переносит его параметр на свойКорутинная функция. Параметр шаблона определяет тип передаваемого параметра. Конструкторsymmetric_coroutine<>::call_typeвыполняет функциюПризнание ссылки наsymmetric_coroutine<>::yield_typeв качестве аргумента. Обоснованиеsymmetric_coroutine<>::call_typeне передает контроль исполнениякорутинной функции- вместо первого вызоваsymmetric_coroutine<>::call_type::operator()синтезируетсимметричный_coroutine<>::yield_typeи передает его как отсылку ккорутинной функции.

Интерфейсsymmetric_coroutine<>::call_typeне содержитget().-функция: нельзя извлекать значения из другого контекста исполнения с этим видом корутинного объекта.

symmetric_coroutine<>::yield_type

symmetric_coroutine<>::yield_type::operator()используется для передачи данных и управления исполнением в другой контекст, вызываяsymmetric_coroutine<>::yield_type::operator().с другимsymmetric_coroutine<>::call_typeв качестве первого аргумента. В качестве альтернативы вы можете передать управление обратно в код, который называетсяsymmetric_coroutine<>::call_type::operator(), называяsymmetric_coroutine<>::yield_type::operator()без аргументаsymmetric_coroutine<>::call_type.

Класс имеет только один шаблонный параметр, определяющий тип передаваемого параметра. Доступ к данным, передаваемым в корутин, осуществляется черезsymmetric_coroutine<>::yield_type::get().

[Important] 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-function

корутинная функциявозвращаетпустотуи принимаетсимметрию_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()призыв.

passing data from main-context to a symmetric-coroutine

Для передачи данных в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
exceptions

Непойманное исключение внутриsymmetric_coroutine<>::call_type'scoroutine-functionвызоветstd::terminate().

[Important] 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] Important

Не прыгайте изнутри блок-уловки, а затем снова бросайте исключение в другой контекст исполнения.

Stack unwinding

Иногда необходимо раскрутить стек незавершенного корутина, чтобы уничтожить локальные переменные стека, чтобы они могли высвобождать выделенные ресурсы (паттерн 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()
Exit a coroutine-function

корутин-функциявыводится с простым ответным утверждением. Это возвращает нас к вызовуsymmetric_coroutine<>::call_type::operator()в начале симметричной корутинной цепи. То есть симметричные корутины не имеют сильного, фиксированного отношения к вызывающему, как и асимметричные корутины.symmetric_coroutine<>::call_typeстановится полным, напримерsymmetric_coroutine<>::call_type::operator boolвернется<false>.

[Important] Important

После возвращения изкорутинной функциикорутинаявляется полным (не может быть возобновлено сsymmetric_coroutine<>::call_type::operator().


PrevUpHomeNext

Статья Symmetric coroutine раздела Chapter 1. Coroutine Coroutine может быть полезна для разработчиков на c++ и boost.




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



:: Главная :: Coroutine ::


реклама


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

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 19:44:16/0.010528087615967/1