Inhoudsopgave 1. Coroutines in C++... 1 1.1. Pull... 1 1.2. Push... 2 1.3. Makefile... 3 1.4. Pull2... 3 1.5. Push2... 4 1.6. Push som... 4 1.7. Link... 5 1. Coroutines in C++ 1.1. Pull De laatste standaard van C++ voorziet nog geen implementatie van coroutines. Daarom wordt hier de Boost bibliotheek gebruikt. Waarschijnlijk komen de Boost coroutines in C++17 terecht. Dit voorbeeld toont hoe de coroutine een reeks getallen genereert. Deze reeks wordt door main() overgenomen. coroutine_pull.cpp coro_t::pull_type source( [&](coro_t::push_type& sink) int first = 1; int second = 1; sink(first); sink(second); for(int i=0;i<8;++i) int third= first + second; first = second; second = third; sink(third); ); std::cout << "main() start\n"; for(auto i:source) std::cout << i << " "; 1
1.2. Push In het bovenstaande voorbeeld is de variabele source gedeclareerd als een pull coroutine. Dat betekent dat je vanuit main() er getallen kan uithalen. Het is main() die de pull doet. In de typedefinitie van coro_t zie je coroutine<int>. Dit wil zeggen dat de doorgegeven data van het int type moet zijn. De source coroutine krijgt een lambdafunctie als parameter. Deze functie zal uitgevoerd worden als coroutine. De lambdafunctie zelf heeft ook een parameter. Dit is sink. Dit is de tegenhanger van pull, namelijk push. Via sink kan de coroutine int getallen doorsturen naar main(). In main() wordt source gebruikt om de doorgegeven getallen op te vangen. Merk op dat er geen echt parallellisme is zoals bij threads. Owel loopt main() ofwel loopt de coroutine. Als één van beide delen een oneindige lus zou maken, komt het andere deel nooit meer aan bod. Bij threads is dat niet zo. Daarom spreekt men bij coroutines ook van coöperatieve multitasking. In dit voorbeeld wordt de richting omgekeerd: main() levert de woorden en de coroutine doet de verwerking ervan. coroutine_push.cpp typedef boost::coroutines2::coroutine<std::string> struct FinalEOL ~FinalEOL() std::cout << std::endl; ; const int num=5, width=15; coro_t::push_type writer( [&](coro_t::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 2
; "peas", "porridge", "hot", "peas", "porridge", "cold", "peas", "porridge", "in", "the", "pot", "nine", "days", "old" std::cout << "main() start\n"; // Dit werkt //begin(writer) = "abc"; // Dit werkt ook writer("def"); writer("ghi"); 1.3. Makefile std::copy(begin(words),end(words),begin(writer)); Bij de compilatie moet je c++11 vermelden, c++14 werkt ook. 1.4. Pull2 all: coroutine_pull coroutine_push coroutine_pull: coroutine_pull.o g++ -o coroutine_pull coroutine_pull.o -lboost_coroutine -lboost_context coroutine_pull.o: coroutine_pull.cpp g++ -c -g -std=c++11 coroutine_pull.cpp coroutine_push: coroutine_push.o g++ -o coroutine_push coroutine_push.o -lboost_coroutine -lboost_context coroutine_push.o: coroutine_push.cpp g++ -c -g -std=c++11 coroutine_push.cpp Dit is een eenvoudiger pull voorbeeld. coroutine_pull2.cpp coro_t::pull_type source( // de constructor start de coroutinefunctie [&](coro_t::push_type& sink) sink(1); // geef 1 door aan de maincontext sink(1); sink(2); sink(3); 3
1.5. Push2 sink(5); sink(8); ); while(source) // ga na of de pull-coroutine nog bestaat int ret = source.get(); // haal de data std::cout << ret << " "; // context-switch naar coroutinefunctie Dit is een eenvoudiger push voorbeeld. coroutine_push2.cpp coro_t::push_type sink( // de constructor start de coroutinefunction NIET [&](coro_t::pull_type& source) for (int i:source) std::cout << i << " "; ); std::vector<int> v1,1,2,3,5,8,13,21,34,55; 1.6. Push som for(int i: v) sink(i); // push i naar de coroutinefunctie En dit is de labooefening. Stuur eerst het aantal door en daarna de getallen volgens het aantal. De coroutine berekent de som. coroutine_push_som.cpp 4
coro_t::push_type sink( [&](coro_t::pull_type& source) int aantal = source.get(); std::cout << "aantal is " << aantal << "\n"; int som = 0; for (int i = 0; i<aantal; i++) int g = source.get(); std::cout << "g is " << g << "\n"; som += g; std::cout << "de som is " << som << "\n"; ); sink(4); // het aantal getallen is 4 1.7. Link sink(1); // 1ste getal sink(2); // 2de getal sink(3); // 3de getal sink(4); // 4de getal std::cout << "einde\n"; http://www.boost.org/doc/libs/1_63_0/libs/coroutine2/doc/html/coroutine2/coroutine/ asymmetric.html 5