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

Asymmetric 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

Два асимметричных типа корутина -asymmetric_coroutine<>::push_typeиasymmetric_coroutine<>::pull_type— обеспечивает однонаправленную передачу данных.

asymmetric_coroutine<>::pull_type

asymmetric_coroutine<>::pull_typeпередает данные из другого контекста исполнения (== извлекается из). Параметр шаблона определяет тип передаваемого параметра. Конструкторasymmetric_coroutine<>::pull_typeвыполняет функциюcoroutine-function), принимая ссылку наasymmetric_coroutine<>::push_typeв качестве аргумента. Обоснованиеasymmetric_coroutine<>::pull_typeпередает управление исполнениемкорутинной функциии комплементарнойасимметричной_coroutine<>::push_typeсинтезируется библиотекой и передается как ссылка накорутин-функцию.

Этот вид корутина обеспечиваетasymmetric_coroutine<>::pull_type::operator(). Этот метод переключает только контекст; он не передает никаких данных.

asymmetric_coroutine<>::pull_typeпредоставляет итераторы вводаasymmetric_coroutine<>::pull_type:::iterator) иstd::begin()/std::end().Перегружены. Прирост-операция переключает контекст и передает данные.

boost::coroutines::asymmetric_coroutine<int>::pull_type source(
    [&](boost::coroutines::asymmetric_coroutine<int>::push_type& sink){
        int first=1,second=1;
        sink(first);
        sink(second);
        for(int i=0;i<8;++i){
            int third=first+second;
            first=second;
            second=third;
            sink(third);
        }
    });
for(auto i:source)
    std::cout << i <<  " ";
output:
1 1 2 3 5 8 13 21 34 55

В этом примереasymmetric_coroutine<>::pull_typeсоздается в контексте основного исполнения с использованием функции лямбда (==coroutine-function), которая вычисляет числа Фибоначчи в простомдля-петли.корутин-функциявыполняется в вновь созданном контексте исполнения, который управляется экземпляромasymmetric_coroutine<>::pull_type.asymmetric_coroutine<>::push_typeавтоматически генерируется библиотекой и передается в качестве ссылки на функцию лямбда. Каждый раз функция лямбда вызываетasymmetric_coroutine<>::push_type::operator()с другим числом Фибоначчи,asymmetric_coroutine<>::push_typeпереносит его обратно в основной контекст исполнения. Местное состояниекорутинной функциисохраняется и будет восстановлено при передаче управления исполнением обратнокорутинной функциидля вычисления следующего числа Фибоначчи. Потому чтоasymmetric_coroutine<>::pull_typeпредоставляет итераторы ввода иstd::begin()/std::end().перегружены,диапазон на основе-петля может использоваться для итерации по генерируемым числам Фибоначчи.

asymmetric_coroutine<>::push_type

asymmetric_coroutine<>::push_typeпередает данные в другой контекст исполнения (== push-to). Параметр шаблона определяет тип передаваемого параметра. Конструкторasymmetric_coroutine<>::push_typeпринимает функциюкорутин-функция, принимая ссылку наасимметричную_корутин<>::pull_typeв качестве аргумента. В отличие отasymmetric_coroutine<>::pull_type, инстанцируяasymmetric_coroutine<>::push_typeне передает контроль исполнениякорутинной функции- вместо первого вызоваasymmetric_coroutine<>::push_type::operator()синтезирует комплементарныйasymmetric_coroutine<>::pull_typeи передает его в качестве ссылки накорутинная функция.

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

asymmetric_coroutine<>::push_typeобеспечивает выходные итераторыasymmetric_coroutine<>::push_type::iteratorиstd::begin()/std::end()перегружены. Прирост-операция переключает контекст и передает данные.

struct FinalEOL{
    ~FinalEOL(){
        std::cout << std::endl;
    }
};
const int num=5, width=15;
boost::coroutines::asymmetric_coroutine<std::string>::push_type writer(
    [&](boost::coroutines::asymmetric_coroutine<std::string>::pull_type& in){
        // finish the last line when we leave by whatever means
        FinalEOL eol;
        // pull values from upstream, lay them out 'num' to a line
        for (;;){
            for(int i=0;i<num;++i){
                // when we exhaust the input, stop
                if(!in) return;
                std::cout << std::setw(width) << in.get();
                // now that we've handled this item, advance to next
                in();
            }
            // after 'num' items, line break
            std::cout << std::endl;
        }
    });
std::vector<std::string> words{
    "peas", "porridge", "hot", "peas",
    "porridge", "cold", "peas", "porridge",
    "in", "the", "pot", "nine",
    "days", "old" };
std::copy(boost::begin(words),boost::end(words),boost::begin(writer));
output:
           peas       porridge            hot           peas       porridge
           cold           peas       porridge             in            the
            pot           nine           days            old

В этом примере aasymmetric_coroutine<>::push_typeсоздается в основном контексте исполнения, принимающем функцию лямбда (==корутин-функция), которая запрашивает строки и выкладывает их «номер» на каждой строке. Это свидетельствует об инверсии контроля, допускаемого корутинами. Без корутина функция полезности для выполнения одной и той же работы обязательно принимает каждое новое значение в качестве параметра функции, возвращаясь после обработки этого единственного значения. Эта функция будет зависеть от статической переменной состояния. Акорутинная функция, однако, может запрашивать каждое новое значение, как бы вызывая функцию, даже если ее вызывающий также передает значения, как если бы вызывая функцию.корутин-функциявыполняется в вновь созданном контексте исполнения, который управляется экземпляромasymmetric_coroutine<>::push_type. Основной контекст исполнения передает строкикорутинной функции, называяасимметричным_coroutine<>::push_type::operator(). Anасимметричным_coroutine<>::pull_typeэкземпляр автоматически генерируется библиотекой и передается в качестве ссылки на функцию лямбда.корутин-функцияполучает доступ к строкам, переданным из основного контекста исполнения, вызываяasymmetric_coroutine<>::pull_type::get()и выкладывает эти строки наstd::coutпо параметрам «номер» и «ширина». Местное состояниекорутинной функциисохраняется и будет восстановлено после передачи управления исполнением обратно.корутинная функция. Потому чтоасимметричная_корутина<>::push_typeобеспечивает выходные итераторы иstd::begin()/std::end()перегружены,std::copyалгоритм может быть использован для итерации по вектору, содержащему строки, и передачи их один за другим в корутин.

coroutine-function

корутин-функциявозвращаетпустотуи принимает в качестве аргумента свой аналог-корутин, так что использование корутина, переданного в качестве аргументакорутин-функция, является единственным способом передачи данных и управления исполнением обратно вызывающему абоненту. Оба корутинных типа используют один и тот же шаблонный аргумент. Дляasymmetric_coroutine<>::pull_typeкорутин-функциявведена вasymmetric_coroutine<>::pull_typeстроительство. Дляasymmetric_coroutine<>::push_typeкорутин-функцияне вводится приasymmetric_coroutine<>::push_typeстроительство, но введенное первым вызовомasymmetric_coroutine<>::push_type::operator(). После возврата управления выполнением изкорутин-функциисостояние корутина может быть проверено черезasymmetric_coroutine<>::pull_type::operator boolreturn<true>, если корутин все еще действителенкорутин-функцияне прекращена. Если первый параметр шаблона не является<void>,<true>также подразумевает, что значение данных доступно.

passing data from a pull-coroutine to main-context

Для передачи данных изasymmetric_coroutine<>::pull_typeк основному контексту фреймворк синтезируетasymmetric_coroutine<>::push_typeсвязан сasymmetric_coroutine<>::pull_typeпример в главном контексте. Синтезированныйasymmetric_coroutine<>::push_typeпередается в качестве аргументакорутинной функции.coroutine-функциядолжна называть этоasymmetric_coroutine<>::push_type::operator()для передачи каждого значения данных обратно в основной контекст. В основном контекстеasymmetric_coroutine<>::pull_type::operator boolопределяет, является ли кодуин все еще действительным и доступно значение данных иликорутин-функцияпрекращенаasymmetric_coroutine<>::pull_typeнедействительна; значения данных нет. Доступ к передаваемому значению данных предоставляется поasymmetric_coroutine<>::pull_type::get().

boost::coroutines::asymmetric_coroutine<int>::pull_type source( // constructor enters coroutine-function
    [&](boost::coroutines::asymmetric_coroutine<int>::push_type& sink){
        sink(1); // push {1} back to main-context
        sink(1); // push {1} back to main-context
        sink(2); // push {2} back to main-context
        sink(3); // push {3} back to main-context
        sink(5); // push {5} back to main-context
        sink(8); // push {8} back to main-context
    });
while(source){            // test if pull-coroutine is valid
    int ret=source.get(); // access data value
    source();             // context-switch to coroutine-function
}
passing data from main-context to a push-coroutine

Для передачи данных вasymmetric_coroutine<>::push_typeиз основного контекста фреймворк синтезируетasymmetric_coroutine<>::pull_typeсвязан сasymmetric_coroutine<>::push_typeпример в главном контексте. Синтезированныйasymmetric_coroutine<>::pull_typeпередается в качестве аргументакорутинной функции. Основной контекст должен называть этоasymmetric_coroutine<>::push_type::operator().для передачи каждого значения данных вкорутинно-функцию. Доступ к передаваемому значению данных даетasymmetric_coroutine<>::pull_type::get().

boost::coroutines::asymmetric_coroutine<int>::push_type sink( // constructor does NOT enter coroutine-function
    [&](boost::coroutines::asymmetric_coroutine<int>::pull_type& source){
        for (int i:source) {
            std::cout << i <<  " ";
        }
    });
std::vector<int> v{1,1,2,3,5,8,13,21,34,55};
for( int i:v){
    sink(i); // push {i} to coroutine-function
}
accessing parameters

К параметрам, возвращаемым изкорутинной функции, можно получить доступ с помощьюasymmetric_coroutine<>::pull_type::get().

Разделение доступа к параметрам из функции переключателя контекста позволяет проверить, асимметричен лиasymmetric_coroutine<>::pull_typeдействителен после возвращения изasymmetric_coroutine<>::pull_type::operator(), напримерasymmetric_coroutine<>::pull_typeимеет значения икорутин-функцияне прекращена.

boost::coroutines::asymmetric_coroutine<boost::tuple<int,int>>::push_type sink(
    [&](boost::coroutines::asymmetric_coroutine<boost::tuple<int,int>>::pull_type& source){
        // access tuple {7,11}; x==7 y==1
        int x,y;
        boost::tie(x,y)=source.get();
    });
sink(boost::make_tuple(7,11));
exceptions

Исключение, брошенное внутриasymmetric_coroutine<>::pull_type'scoroutine-functionперед его первым вызовомasymmetric_coroutine<>::push_type::operator()будет переброшенasymmetric_coroutine<>::pull_typeКонструктор. Послеasymmetric_coroutine<>::pull_type'scoroutine-functionпервый звонокasymmetric_coroutine<>::push_type::operator(), любое последующее исключение в том, чтокорутин-функциябудет повторно сброшенаасимметричным_coroutine<>::pull_type::operator().асимметричным_coroutine<>::pull_type::get()не бросает.

Исключение, брошенное внутриasymmetric_coroutine<>::push_type'sкорутин-функции, будет повторно брошеноasymmetric_coroutine<>::push_type::operator().

[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::asymmetric_coroutine<void>::push_type sink(
        [&](boost::coroutines::asymmetric_coroutine<void>::pull_type& source){
            X x;
            for(int=0;;++i){
                std::cout<<"fn(): "<<i<<std::endl;
                // transfer execution control back to main()
                source();
            }
        });
    sink();
    sink();
    sink();
    sink();
    sink();
    std::cout<<"sink is complete: "<<std::boolalpha<<!sink<<"\n";
}
output:
    X()
    fn(): 0
    fn(): 1
    fn(): 2
    fn(): 3
    fn(): 4
    fn(): 5
    sink is complete: false
    ~X()
Range iterators

Boost.Coroutineпредоставляет выходные и входные указатели, используяBoost.Range.asymmetric_coroutine<>::pull_typeможет использоваться с помощью входных устройств, использующихstd::begin()иstd::end().

int number=2,exponent=8;
boost::coroutines::asymmetric_coroutine< int >::pull_type source(
    [&]( boost::coroutines::asymmetric_coroutine< int >::push_type & sink){
        int counter=0,result=1;
        while(counter++<exponent){
            result=result*number;
            sink(result);
        }
    });
for (auto i:source)
    std::cout << i <<  " ";
output:
    2 4 8 16 32 64 128 256

asymmetric_coroutine<>::pull_type::iterator::operator++()соответствуетasymmetric_coroutine<>::pull_type::operator();asymmetric_coroutine<>::pull_type::iterator::operator*()примерно соответствуетasymmetric_coroutine<>::pull_type::get(). Итератор, первоначально полученный изstd::begin()asymmetric_coroutine<>::pull_typeсравнивается с итератором, полученным изstd::end()того жеasymmetric_coroutine<>::pull_type, когда егоasymmetric_coroutine<>::pull_type::operator boolвернулся бы<false>.

[Note] Note

Если<T>является только движущимся типом, тоасимметричен_coroutine< T>::pull_type::iteratorможет быть отменен только один раз, прежде чем он будет увеличен снова.

Производители могут быть созданы изasymmetric_coroutine<>::push_type.

boost::coroutines::asymmetric_coroutine<int>::push_type sink(
    [&](boost::coroutines::asymmetric_coroutine<int>::pull_type& source){
        while(source){
            std::cout << source.get() <<  " ";
            source();
        }
    });
std::vector<int> v{1,1,2,3,5,8,13,21,34,55};
std::copy(boost::begin(v),boost::end(v),boost::begin(sink));

asymmetric_coroutine<>::push_type::iterator::operator*()примерно соответствуетasymmetric_coroutine<>::push_type::operator(). Итератор, первоначально полученный изstd::begin()asymmetric_coroutine<>::push_typeсравнивается с итератором, полученным изstd::end()того жеasymmetric_coroutine<>::push_type, когда егоasymmetric_coroutine<>::push_type::operator boolвернется<false>.

Exit a coroutine-function

корутин-функциявыводится с простым заявлением о возврате, возвращающимся к процедуре вызова.asymmetric_coroutine<>::pull_type,asymmetric_coroutine<>::push_typeстановится полным, напримерasymmetric_coroutine<>::pull_type::operator bool,asymmetric_coroutine<>::push_type::operator boolвернется<false>.

[Important] Important

После возвращения изкорутин-функциизавершенакорутина(не может быть возобновлена сasymmetric_coroutine<>::push_type::operator(),asymmetric_coroutine<>::pull_type::operator()).


PrevUpHomeNext

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




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



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


реклама


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

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 18:07:02/0.0077109336853027/1