C++ korutin példák

C Korutin Peldak



A korutinok olyan nyelvi funkciót biztosítanak, amely lehetővé teszi az aszinkron kódok rendezettebb és lineárisabb megírását, elősegítve a strukturált és szekvenciális megközelítést. Mechanizmust biztosítanak a függvény végrehajtásának szüneteltetésére és újraindítására bizonyos esetekben anélkül, hogy a teljes szálat leállítanák. A korutinok hasznosak olyan feladatok kezelésében, amelyek várakozást igényelnek az I/O műveletekre, mint például egy fájl olvasása vagy hálózati hívás küldése.

A korutinok a generátorok koncepcióján alapulnak, ahol a függvény értékeket adhat, és később folytathatja a végrehajtást. A korutinok hatékony eszközt biztosítanak az aszinkron műveletek kezeléséhez, és nagymértékben javíthatják a kód általános minőségét.

A korutinok felhasználása

A korutinokra több okból is szükség van a modern programozásban, különösen az olyan nyelvekben, mint a C++. Íme néhány fő ok, amiért a korutin hasznos:







A korutinok elegáns megoldást nyújtanak az aszinkron programozáshoz. Lehetővé teszik egy olyan kód létrehozását, amely szekvenciálisnak tűnik, és blokkolja, amelyet egyszerűbb megfontolni és megérteni. A korutinok bizonyos pontokon felfüggeszthetik végrehajtásukat a szálak blokkolása nélkül, lehetővé téve más feladatok párhuzamos működését. Emiatt a rendszer erőforrásai hatékonyabban használhatók fel, és az I/O műveleteket magába foglaló vagy külső eseményekre váró alkalmazásokban megnő a válaszkészség.



Ezek megkönnyíthetik a kód megértését és karbantartását. Az összetett visszahívási láncok vagy állapotgépek kiiktatásával a korutinok lehetővé teszik a kód lineárisabb és szekvenciálisabb stílusban történő megírását. Ez javítja a kódszervezést, csökkenti a beágyazást, és könnyen érthetővé teszi a logikát.



A korutinok strukturált módot biztosítanak az egyidejűség és a párhuzamosság kezelésére. Lehetővé teszik az összetett koordinációs minták és aszinkron munkafolyamatok kifejezését egy intuitívabb szintaxis használatával. A hagyományos szálfűzési modellekkel ellentétben, ahol a szálak blokkolva lehetnek, a korutinok felszabadíthatják a rendszer erőforrásait, és hatékony többfeladatos munkavégzést tesznek lehetővé.





Hozzunk létre néhány példát a korutinok megvalósításának bemutatására C++ nyelven.

1. példa: Alapvető korutinok

Az alapvető korutin példája az alábbiakban található:



#include

#include

struct ThisCorout {

struct ígéret_típus {

ThisCorout get_return_object ( ) { Visszatérés { } ; }

std :: felfüggeszt_soha kezdeti_felfüggesztés ( ) { Visszatérés { } ; }

std :: felfüggeszt_soha final_suspend ( ) nem, kivéve { Visszatérés { } ; }

üres nem kezelt kivétel ( ) { }

üres return_void ( ) { }

} ;

bool await_ready ( ) { Visszatérés hamis ; }

üres await_suspend ( std :: coroutine_handle <> h ) { }

üres await_resume ( ) { std :: cout << – A Coroutine folytatódik. << std :: endl ; }

} ;

ThisCorout foo ( ) {

std :: cout << – Elkezdődött a korutin. << std :: endl ;

co_await std :: felfüggeszt_mindig { } ;

co_return ;

}

int fő- ( ) {

auto cr = foo ( ) ;

std :: cout << 'A korutína létrejött.' << std :: endl ;

cr. await_resume ( ) ;

std :: cout << – A korutin véget ért. << std :: endl ;

Visszatérés 0 ;

}

Nézzük át a korábban megadott kódot, és magyarázzuk el részletesen:

A szükséges fejlécfájlok megadása után meghatározzuk a „ThisCorout” struktúrát, amely egy korutint képvisel. A „ThisCorout”-on belül egy másik „promise_type” struktúra van definiálva, amely kezeli a korutin ígéretét. Ez a struktúra különféle funkciókat biztosít, amelyekre a korutin gépezetnek szüksége van.

A zárójelben a get_return_object() függvényt használjuk. Magát a korutin objektumot adja vissza. Ebben az esetben egy üres „ThisCorout” objektumot ad vissza. Ezután a kezdeti_suspend() függvény meghívásra kerül, amely meghatározza a korutint első indításakor bekövetkező viselkedést. Az std::suspend_never azt jelenti, hogy a korutint nem szabad kezdetben felfüggeszteni.

Ezt követően van a final_suspend() függvény, amely meghatározza a viselkedést, amikor a korutin hamarosan befejeződik. Az std::suspend_never azt jelenti, hogy a korutint nem szabad felfüggeszteni a véglegesítése előtt.

Ha egy korutin kivételt dob, akkor az unhandled_exception() metódus kerül meghívásra. Ebben a példában ez egy üres függvény, de szükség szerint kezelheti a kivételeket. Amikor a korutin érték megadása nélkül fejeződik be, a return_void() metódus meghívásra kerül. Ebben az esetben ez is egy üres függvény.

Három tagfüggvényt is meghatározunk a „ThisCorout”-on belül. Az await_ready() függvény meghívása annak ellenőrzésére, hogy a korutin készen áll-e a végrehajtás folytatására. Ebben a példában mindig false értéket ad vissza, ami azt jelzi, hogy a korutin nem áll készen az azonnali folytatásra. Amikor a korutint felfüggesztik, az await_suspend() metódus kerül meghívásra. Itt ez egy üres funkció, ami azt jelenti, hogy nincs szükség felfüggesztésre. A program meghívja az await_resume() függvényt, amikor a korutint a felfüggesztés után folytatják. Csak egy üzenetet ad ki, amely kijelenti, hogy a korutin újraindult.

A kód következő sorai a foo() corutine függvényt határozzák meg. A foo()-ban először egy üzenetet nyomtatunk, amely kijelenti, hogy a korutin elindult. Ezután a co_await std::suspend_always{} a korutint felfüggesztésére használja, és jelzi, hogy egy későbbi időpontban újraindítható. A co_return utasítás a korutint érték visszaadása nélkül fejezi be.

A main() függvényben egy „ThisCorout” típusú „cr” objektumot készítünk a foo() meghívásával. Ez létrehozza és elindítja a korutint. Ezután egy üzenetet nyomtat, amely jelzi, hogy a korutint létrehozták. Ezután meghívjuk az await_resume()-t a „cr” korutine objektumon a végrehajtás folytatásához. Az await_resume()-ban megjelenik a „A korutin folytatása” üzenet. Végül megjelenítünk egy üzenetet, amely kijelenti, hogy a korutint a program leállása előtt befejeződött.

A program futtatásakor a kimenet a következő:

2. példa: Korutin paraméterekkel és hozamgal

Most, ehhez az illusztrációhoz adunk egy kódot, amely bemutatja a paraméterekkel rendelkező korutinok használatát C++-ban, hogy generátorszerű viselkedést hozzon létre számsorozat létrehozásához.

#include

#include

#include

struct ÚJKorutin {

struct p_type {

std :: vektor < int > értékeket ;

NEWCoroutine get_return_object ( ) { Visszatérés { } ; }

std :: felfüggeszt_mindig kezdeti_felfüggesztés ( ) { Visszatérés { } ; }

std :: felfüggeszt_mindig final_suspend ( ) nem, kivéve { Visszatérés { } ; }

üres nem kezelt kivétel ( ) { }

üres return_void ( ) { }

std :: felfüggeszt_mindig hozam_érték ( int érték ) {

értékeket. visszavet ( érték ) ;

Visszatérés { } ;

}

} ;

std :: vektor < int > értékeket ;

struct iterátor {

std :: coroutine_handle <> chorus_handle ;

bool operátor != ( const iterátor & Egyéb ) const { Visszatérés chorus_handle != Egyéb. chorus_handle ; }

iterátor & operátor ++ ( ) { chorus_handle. önéletrajz ( ) ; Visszatérés * ez ; }

int operátor * ( ) const { Visszatérés chorus_handle. ígéret ( ) . értékeket [ 0 ] ; }

} ;

az iterátor elindul ( ) { Visszatérés iterátor { std :: coroutine_handle < p_type >:: from_promise ( ígéret ( ) ) } ; }

iterátor vége ( ) { Visszatérés iterátor { nullptr } ; }

std :: coroutine_handle < p_type > ígéret ( ) { Visszatérés
std :: coroutine_handle < p_type >:: from_promise ( * ez ) ; }

} ;

NEWCoroutine generálNumbers ( ) {

co_yield 5 ;

co_yield 6 ;

co_yield 7 ;

}

int fő- ( ) {

NEWCoroutine nc = generNumbers ( ) ;

számára ( int érték : nc ) {

std :: cout << érték << ' ' ;

}

std :: cout << std :: endl ;

Visszatérés 0 ;

}

Az előző kódban a NEWCoroutine struktúra korutin alapú generátort jelent. Tartalmaz egy beágyazott „p_type” struktúrát, amely ígérettípusként szolgál a korutin számára. A p_type struktúra határozza meg azokat a függvényeket, amelyekre a korutin gépezetnek szüksége van, mint például a get_return_object(), a kezdeti_suspend(), a final_suspend(), az unhandled_exception() és a return_void(). A p_type struktúra tartalmazza a result_value(int value) függvényt is, amely a korutinból származó értékek előállítására szolgál. A megadott értéket hozzáadja az értékvektorhoz.

A NEWCoroutine struktúra tartalmazza az std::vector tagváltozót, az úgynevezett „értékeket”, amely a generált értékeket reprezentálja. A NEWCoroutine-on belül van egy beágyazott struktúra iterátor, amely lehetővé teszi a generált értékek feletti iterációt. Tartalmazza a coro_handle-t, amely a korutint kezeli, és meghatározza az olyan operátorokat, mint a !=, ++ és * az iterációhoz.

A begin() függvényt használjuk egy iterátor létrehozására a korutín elején úgy, hogy megkapjuk a coro_handle paramétert a p_type ígéretből. Míg az end() függvény egy iterátort hoz létre, amely a korutin végét reprezentálja, és nullptr coro_handle-lel van felépítve. Ezt követően az ígéret() függvényt használjuk az ígéret típusának visszaadására úgy, hogy létrehozunk egy coroutine_handle-t a p_type ígéretből. A generateNumbers() függvény egy korutin, amely a co_yield kulcsszó használatával három értéket ad – 5, 6 és 7.

A main() függvényben a NEWCoroutine „nc” nevű példánya jön létre a generateNumbers() korutin meghívásával. Ez inicializálja a korutint és rögzíti az állapotát. Egy tartomány alapú 'for' ciklust használnak az 'nc' értékei áttételére, és minden egyes érték kinyomtatásra kerül, amelyeket szóközzel választanak el az std::cout használatával.

A generált kimenet a következő:

Következtetés

Ez a cikk a korutinok használatát mutatja be C++ nyelven. Két példát tárgyaltunk. Az első szemléltetésre az alap korutint egy C++ programban hozzuk létre a korutin függvények segítségével. Míg a második demonstrációt a korutinok paraméterekkel való felhasználásával végeztük, és engedve generátorszerű viselkedést generáltunk egy számsorozat létrehozásához.