Commençons --Pourquoi cette vidéo -C obs_scene(SCENE_WEBCAM); Depuis quelques années, il y a eu plusieurs vidéos et présentations pour expiiquer le fonctionnement des coroutines en C++. Pourquoi tant d'effort ? Parce que C++ propose quelque chose d'innédit, de nouveau, permettant de faire tout ce qui se faisait déjà et beaucoup plus. -P -C resetdocument(); -C obs_scene(SCENE_TABLEAU); -T -B C++20 -b Début des coroutines Les coroutines sont officiellement apparues dans le standard C++ avec la norme C++20 (2020). Mais ce qui a été publié, c'est juste les modifications au niveau du language, soit de nouveau opérateurs et une explication du role du compilatateur. -B Mais pas de librairies en faisant usage. -b Les gens ne savaient pas trop comment utiliser cela. -b Ça aurait pu juste ressembler à ce qu'il y a dans d'autres languages. -b Mais ce n'était pas le cas. -b Le champ d'application du C++ est énorme (design space) -B Aujoutd'hui, les choses ont changé Vous pouvez apprendre l'essentiel d'une de ces librairies en quelques heures. Ou juste en regardant un exemple. -b boost::asio -b boost::cobalt -B Mais ça ne règle pas tout -b on pourrait faire plus -b c'est un peu le but de cette vidéo -b En sachant comment ça fonctionne, plus de gens auront des idées --Rapidement, une coroutine, c'est -C resetdocument(); -C obs_scene(SCENE_TABLEAU); -T -B Ça ressemble à une sous-routine (fonction) c++ normale -# int endy = textbox (1300,70,"sous-routine",{ "void foo(){", " ...", " read(...); // le programme est bloqué", " ...", "}" }); -# -P -b Mais ça peut s'arrêter en plein milieu -b Ça laisse d'autres coroutines avancer -# textbox (1300,endy+30,"coroutine",{ "TASK foo(){", " ...", " // En attendant le co_await", " // on peut faire autre chose", " // (autres coroutines)", " co_await async_read(...);", " ...", "}" }); -# -B Exécuter plusieurs bout de code en parallèle. -b On alterne entre plusieurs coroutine -B Chef d'orchestre -b Il peut y avoir un chef d'orchestre (scheduler) -b ou pas -B Coopération -b Parfois 2 ou plusieurs coroutine s'échange le controle. --Coroutines sans pile -C resetdocument(); -C obs_scene(SCENE_TABLEAU); -T -B Voici une coroutine tel qu'écrite -# int endy = textbox(1300,70,"Coroutine",{ "std::generator foo (int nb){", " int a = 1;", " a += nb;", " co_yield a;", " int b = 1;", " b = a + nb;", " co_yield b;", "}" }); -# -B Voici une coroutine (convertie) sans pile -# textbox(1300,endy+30,"",{ "class coro{", " int a = 1;", " int b = 1;", " coro(){", " return generator;", " }", " run (int nb){", " a += nb;", " co_yield a;", " b = a + nb;", " co_yield b;", " }", "}" }); -# --Bizarreries dans le language -C resetdocument(); -C obs_scene(SCENE_TABLEAU); -T Ce n'est pas si bizarre, mais ça à l'air un peu, au moins à première vue. -B La signature des coroutines -b TASK for (int nb); -b Ça semble une fonction standard -b Ça retourne un objet de type TASK -b Mais ... -# int endy = textbox (1300,70,"Coroutine",{ "TASK foo (int nb){", " ...", " co_return;", "}" }); -# -B Étrange surcharge (overload) Ce ne sont pas des surcharges, mais ça semble être ça. -# textbox (1300,endy+30,"Awaitable",{ "struct Awaitable{", " bool await_ready();", " void|bool|coroutine_handle<> await_suspend(", " coroutine_handle);", " void|type await_resume();", "}" }); -# --Chef d'orchestre (schedular) -C resetdocument(); -C obs_scene(SCENE_TABLEAU); -T -B Boucles d'évènements (event loop) -b Voici une série de requêtes asynchrones -P -# SIZE selm{90,50}; int posx = 1600; int stepx = 150; COOR pos1(posx-2*stepx,100); string chef1("chef1"); add_delay(2000); int stime = 300; addelm(chef1,"Chef",ELM_ELLIPSE,{posx,250},{150,50}); for (int i=0; i<5; i++){ string id = string_f("id1-%d",i); string name = string_f("r%d",i); add_delay(stime); addelm(id,name,ELM_RECT,pos1.move(i*stepx,0),selm); add_delay(stime); connect(id,chef1,1); add_delay(stime); connect(id,chef1,0); } -# -P -C connect (chef1,"id1-0",1); -P -C connect (chef1,"id1-0",4); -P -C connect (chef1,"id1-0",0); -B Coroutines et chef d'orchestre -# string chef2("chef2"); COOR pos2(posx-2*stepx,400); addelm(chef2,"Chef",ELM_ELLIPSE,{posx,550},{150,50}); for (int i=0; i<5; i++){ string id = string_f("id2-%d",i); string name = string_f("c%d",i); addelm(id,name,ELM_RECT,pos2.move(i*stepx,0),selm); connect (id,chef2,1); } -# -b À l'envers des boucles d'évènements -b Programmation plus simple -P -C connect ("id2-0",chef2,4); -P -C connect ("id2-0",chef2,1); -B Collaboration entre 2 coroutines --La trappe des coroutines