Przykłady współprogramów C++

Przyklady Wspolprogramow C



Współprogramy zapewniają funkcję językową, która umożliwia pisanie kodu asynchronicznego w bardziej zorganizowany i liniowy sposób, promując podejście strukturalne i sekwencyjne. Dają mechanizm wstrzymywania i wznawiania wykonywania funkcji w określonych przypadkach bez zatrzymywania całego wątku. Współprogramy są pomocne podczas obsługi zadań wymagających oczekiwania na operacje we/wy, takich jak odczyt z pliku lub wysyłanie połączenia sieciowego.

Współprogramy opierają się na koncepcji generatorów, w których funkcja może dawać wartości, a później zostać wznowiona w celu kontynuowania wykonywania. Współprogramy zapewniają potężne narzędzie do zarządzania operacjami asynchronicznymi i mogą znacznie poprawić ogólną jakość kodu.

Zastosowania współprogramów

Współprogramy są potrzebne z kilku powodów we współczesnym programowaniu, szczególnie w językach takich jak C++. Oto kilka kluczowych powodów, dla których współprogramy są korzystne:







Współprogramy stanowią eleganckie rozwiązanie do programowania asynchronicznego. Umożliwiają utworzenie kodu, który wygląda na sekwencyjny i blokujący, który jest łatwiejszy do zrozumienia i zrozumienia. Współprogramy mogą wstrzymywać swoje wykonanie w określonych punktach bez blokowania wątków, umożliwiając równoległe wykonywanie innych zadań. Dzięki temu zasoby systemowe mogą być wykorzystywane efektywniej, a responsywność zwiększona w aplikacjach wymagających operacji wejścia/wyjścia lub oczekiwania na zdarzenia zewnętrzne.



Mogą sprawić, że kod będzie łatwiejszy do zrozumienia i utrzymania. Eliminując złożone łańcuchy wywołań zwrotnych lub maszyny stanu, współprogramy umożliwiają pisanie kodu w bardziej liniowym i sekwencyjnym stylu. Poprawia to organizację kodu, ogranicza zagnieżdżanie i sprawia, że ​​logika jest łatwa do zrozumienia.



Współprogramy zapewniają ustrukturyzowany sposób obsługi współbieżności i równoległości. Pozwalają wyrazić złożone wzorce koordynacji i asynchroniczne przepływy pracy przy użyciu bardziej intuicyjnej składni. W przeciwieństwie do tradycyjnych modeli wątków, w których wątki mogą być blokowane, współprogramy mogą zwolnić zasoby systemowe i umożliwić wydajną wielozadaniowość.





Stwórzmy kilka przykładów demonstrujących implementację współprogramów w C++.

Przykład 1: Podstawowe współprogramy

Podstawowy przykład współprogramów przedstawiono poniżej:



#include

#include

struktura To Corout {

struktura typ_obietnicy {

ThisCorout get_return_object ( ) { powrót { } ; }

st :: zawieszaj_nigdy początkowe_zawieszenie ( ) { powrót { } ; }

st :: zawieszaj_nigdy ostateczne_zawieszenie ( ) nie, z wyjątkiem { powrót { } ; }

próżnia nieobsługiwany wyjątek ( ) { }

próżnia powrót_void ( ) { }

} ;

bool oczekuj_gotowy ( ) { powrót FAŁSZ ; }

próżnia oczekiwanie_zawieszenie ( st :: uchwyt_korutyny <> H ) { }

próżnia oczekiwanie na wznowienie ( ) { st :: cout << „Korutyna została wznowiona.” << st :: koniec ; }

} ;

To Corout foo ( ) {

st :: cout << „Rozpoczęła się korutyna”. << st :: koniec ;

co_await std :: zawieszaj_zawsze { } ;

współ_powrót ;

}

wew główny ( ) {

automatyczny kr = bla ( ) ;

st :: cout << „Utworzono współprogram”. << st :: koniec ;

kr. oczekiwanie na wznowienie ( ) ;

st :: cout << „Korutyna skończona.” << st :: koniec ;

powrót 0 ;

}

Przeanalizujmy wcześniej podany kod i wyjaśnijmy go szczegółowo:

Po dołączeniu wymaganych plików nagłówkowych definiujemy strukturę „ThisCorout”, która reprezentuje współprogram. Wewnątrz „ThisCorout” zdefiniowano inną strukturę o nazwie „promise_type”, która obsługuje współprogramową obietnicę. Struktura ta zapewnia różne funkcje wymagane przez maszynę współprogramową.

Wewnątrz nawiasów używamy funkcji get_return_object(). Zwraca sam obiekt współprogramu. W tym przypadku zwraca pusty obiekt „ThisCorout”. Następnie wywoływana jest funkcja origin_suspend(), która określa zachowanie przy pierwszym uruchomieniu współprogramu. Std::suspend_never oznacza, że ​​współprogram nie powinien być początkowo zawieszany.

Następnie mamy funkcję final_suspend(), która określa zachowanie, gdy współprogram dobiegnie końca. Std::suspend_never oznacza, że ​​współprogram nie powinien być zawieszany przed jego sfinalizowaniem.

Jeśli współprogram zgłasza wyjątek, wywoływana jest metoda unhandled_exception(). W tym przykładzie jest to pusta funkcja, ale w razie potrzeby możesz obsłużyć wyjątki. Kiedy współprogram kończy się, nie dając wartości, wywoływana jest metoda return_void(). W tym przypadku jest to również pusta funkcja.

W ramach „ThisCorout” definiujemy także trzy funkcje członkowskie. Funkcja czekaj_ready() jest wywoływana w celu sprawdzenia, czy współprogram jest gotowy do wznowienia wykonywania. W tym przykładzie zawsze zwraca wartość false, co wskazuje, że współprogram nie jest gotowy do natychmiastowego wznowienia. Kiedy współprogram ma zostać zawieszony, wywoływana jest metoda oczekuj_suspend(). Tutaj jest to pusta funkcja, co oznacza, że ​​nie jest konieczne żadne zawieszenie. Program wywołuje funkcję czekania_resume(), gdy współprogram jest wznawiany po zawieszeniu. Po prostu wyświetla komunikat stwierdzający, że współprogram został wznowiony.

Kolejne linie kodu definiują funkcję współprogramu foo(). Wewnątrz funkcji foo() zaczynamy od wydrukowania komunikatu stwierdzającego, że współprogram został uruchomiony. Następnie co_await std::suspend_always{} służy do zawieszenia współprogramu i wskazuje, że można go wznowić w późniejszym momencie. Instrukcja co_return służy do zakończenia współprogramu bez zwracania żadnej wartości.

W funkcji main() konstruujemy obiekt „cr” typu „ThisCorout”, wywołując foo(). Spowoduje to utworzenie i uruchomienie współprogramu. Następnie drukowany jest komunikat informujący, że współprogram został utworzony. Następnie wywołujemy funkcję oczekuj_resume() na obiekcie współprogramu „cr”, aby wznowić jego wykonywanie. Wewnątrz funkcji oczekuj_resume() drukowany jest komunikat „Koprogramacja została wznowiona”. Na koniec wyświetlamy komunikat informujący, że współprogram jest ukończony przed zakończeniem programu.

Po uruchomieniu tego programu wynik jest następujący:

Przykład 2: Współprogram z parametrami i wydajnością

Teraz, na potrzeby tej ilustracji, udostępniamy kod demonstrujący użycie współprogramów z parametrami i wydajnością w C++ w celu stworzenia zachowania podobnego do generatora w celu wygenerowania sekwencji liczb.

#include

#include

#uwzględnij

struktura NOWOŚĆKorutyna {

struktura typ_p {

st :: wektor < wew > wartości ;

NOWOŚĆKoordynacja get_return_object ( ) { powrót { } ; }

st :: zawieszaj_zawsze początkowe_zawieszenie ( ) { powrót { } ; }

st :: zawieszaj_zawsze ostateczne_zawieszenie ( ) nie, z wyjątkiem { powrót { } ; }

próżnia nieobsługiwany wyjątek ( ) { }

próżnia powrót_void ( ) { }

st :: zawieszaj_zawsze wartość_zysku ( wew wartość ) {

wartości. push_back ( wartość ) ;

powrót { } ;

}

} ;

st :: wektor < wew > wartości ;

struktura iterator {

st :: uchwyt_korutyny <> chorus_handle ;

operator boolowy != ( konst iterator & Inny ) konst { powrót chorus_handle != Inny. chorus_handle ; }

iterator & operator ++ ( ) { chorus_handle. wznawiać ( ) ; powrót * Ten ; }

wew operator * ( ) konst { powrót chorus_handle. obietnica ( ) . wartości [ 0 ] ; }

} ;

rozpoczyna się iterator ( ) { powrót iterator { st :: uchwyt_korutyny < typ_p >:: z_obietnicy ( obietnica ( ) ) } ; }

koniec iteratora ( ) { powrót iterator { nullptr } ; }

st :: uchwyt_korutyny < typ_p > obietnica ( ) { powrót
st :: uchwyt_korutyny < typ_p >:: z_obietnicy ( * Ten ) ; }

} ;

NOWOŚĆKoordynacja generujeNumbers ( ) {

współ_wydajność 5 ;

współ_wydajność 6 ;

współ_wydajność 7 ;

}

wew główny ( ) {

NOWOŚĆKorutyna nc = wygeneruj liczby ( ) ;

Do ( wew wartość : nc ) {

st :: cout << wartość << ' ' ;

}

st :: cout << st :: koniec ;

powrót 0 ;

}

W poprzednim kodzie struktura NEWCoroutine reprezentuje generator oparty na współprogramie. Zawiera zagnieżdżoną strukturę „p_type”, która służy jako typ obietnicy dla współprogramu. Struktura p_type definiuje funkcje wymagane przez maszynę współprogramową, takie jak get_return_object(), Individual_suspend(), final_suspend(), unhandled_exception() i return_void(). Struktura p_type zawiera również funkcję Yield_value(int value), która służy do zwracania wartości z współprogramu. Dodaje podaną wartość do wektora wartości.

Struktura NEWCoroutine zawiera zmienną składową std::vector zwaną „wartościami”, która reprezentuje wygenerowane wartości. Wewnątrz NEWCoroutine znajduje się zagnieżdżony iterator struktury, który pozwala na iterację po wygenerowanych wartościach. Zawiera coro_handle, który jest uchwytem współprogramu i definiuje operatory takie jak !=, ++ i * dla iteracji.

Używamy funkcji Begin(), aby utworzyć iterator na początku współprogramu, uzyskując coro_handle z obietnicy p_type. Natomiast funkcja end() tworzy iterator reprezentujący koniec współprogramu i jest skonstruowany z wartością nullptr coro_handle. Następnie funkcja Promise() jest wykorzystywana do zwrócenia typu obietnicy poprzez utworzenie uchwytu coroutine z obietnicy p_type. Funkcja generateNumbers() to współprogram, który zwraca trzy wartości – 5, 6 i 7 – przy użyciu słowa kluczowego co_yield.

W funkcji main() instancja NEWCoroutine o nazwie „nc” jest tworzona poprzez wywołanie współprogramu generateNumbers(). To inicjuje współprogram i przechwytuje jego stan. Do iteracji po wartościach „nc” używana jest pętla „for” oparta na zakresach, a każda wartość jest drukowana i oddzielana spacją za pomocą std::cout.

Wygenerowane dane wyjściowe są następujące:

Wniosek

W tym artykule pokazano wykorzystanie współprogramów w C++. Omówiliśmy dwa przykłady. Na pierwszej ilustracji podstawowa współprogram jest tworzona w programie C++ przy użyciu funkcji współprogramu. Podczas gdy druga demonstracja została przeprowadzona poprzez wykorzystanie współprogramów z parametrami i ustępowaniem w celu wygenerowania zachowania podobnego do generatora w celu utworzenia sekwencji liczb.