Maison >développement back-end >C++ >Explication détaillée de la programmation coroutine en C++

Explication détaillée de la programmation coroutine en C++

WBOY
WBOYoriginal
2023-08-22 12:18:251176parcourir

Explication détaillée de la programmation coroutine en C++

Avec le développement continu de la technologie informatique, les méthodes de programmation innovent et s'améliorent également constamment. Parmi eux, la programmation par coroutines est considérée comme une méthode de programmation relativement nouvelle. La programmation coroutine a été proposée pour la première fois en 1958 par Melvin Conway dans son article. Mais c’est le langage C++ qui promeut et applique véritablement la programmation coroutine. Par conséquent, cet article analysera et expliquera en détail la programmation coroutine du point de vue du langage C++.

Qu'est-ce qu'une coroutine ?

Avant d'expliquer la programmation de la coroutine, nous devons d'abord comprendre ce qu'est la coroutine. Les coroutines peuvent être simplement comprises comme une sous-fonction spéciale qui peut être suspendue lorsque l'exécution atteint un point spécifique et attendre son réveil avant de poursuivre l'exécution. Par rapport aux appels de fonction traditionnels, la méthode d'exécution des coroutines est plus flexible.

La suspension et le réveil de la coroutine peuvent être contrôlés par elle-même, et non par l'appelant. L'avantage de ceci est que lorsque la coroutine effectue certaines opérations à long terme, elle peut abandonner les ressources du processeur et laisser d'autres tâches être effectuées, permettant ainsi une meilleure utilisation des ressources informatiques.

En C++, les coroutines peuvent être implémentées en utilisant le mot-clé co_await, qui permet à une coroutine d'être suspendue lorsque l'exécution atteint un certain point et de se réveiller après avoir atteint des conditions prédéfinies.

Comment utiliser les coroutines ?

En C++, l'utilisation de coroutines nécessite l'aide d'une bibliothèque de coroutines. Actuellement, les bibliothèques de coroutines les plus couramment utilisées sont Boost.Coroutine et la bibliothèque de coroutines fournie avec C++20. Prenons l'exemple des coroutines en C++20 pour expliquer comment utiliser les coroutines.

  1. Définir les fonctions coroutine

En C++20, nous pouvons utiliser le mot-clé co_await et le mot-clé co_yield pour définir les fonctions coroutine. co_await signifie suspendre la coroutine actuelle et attendre d'être réveillée, tandis que co_yield signifie suspendre la coroutine actuelle et renvoyer certaines valeurs ou statuts lorsque la fonction coroutine atteint un certain point. Voici un exemple simple de fonction coroutine :

#include <iostream>
#include <coroutine>
using namespace std;
 
struct HelloWorld {
    struct promise_type {
        HelloWorld get_return_object() {
            return {};
        }
        std::suspend_never initial_suspend() {
            return {};
        }
        std::suspend_never final_suspend() noexcept {
            return {};
        }
        void unhandled_exception() {}
    };
    
    HelloWorld() {};
    void print() {
        cout << "Hello, world!" << endl;
    }
 
    void operator()() {}
};
 
int main() {
    HelloWorld hello_world;
    hello_world();
    hello_world.print();
    return 0;
}

Dans l'exemple ci-dessus, nous définissons une structure nommée HelloWorld, qui est une fonction coroutine. Dans cette structure, nous implémentons une structure imbriquée appelée promise_type, qui contrôle le comportement de la fonction coroutine. Nous définissons également une fonction membre appelée print, qui imprime la chaîne "Hello, world!".

  1. Appelez la fonction coroutine

En C++20, nous pouvons utiliser la classe coroutine_handle pour contrôler l'état d'exécution de la coroutine. Avant d'appeler la fonction coroutine, nous devons obtenir un objet coroutine_handle. Une fois la fonction coroutine exécutée, nous devons libérer manuellement l'objet. L'exemple est le suivant :

int main() {
    HelloWorld hello_world;
    auto handle = hello_world();
    handle.resume();
    hello_world.print();
    handle.destroy();
    return 0;
}

Dans l'exemple ci-dessus, nous obtenons d'abord un objet coroutine_handle, puis appelons sa fonction curriculum vitae(), qui exécutera le code dans la fonction coroutine jusqu'à ce que le mot-clé co_await ou co_yield soit rencontré. coroutine actuelle. Enfin, nous appelons manuellement la fonction destroy() pour libérer la coroutine.

  1. Utilisez co_await et co_yield dans la fonction coroutine

Dans la fonction coroutine, nous pouvons suspendre la coroutine via les mots-clés co_await et co_yield. Voici un exemple :

#include <iostream>
#include <coroutine>
using namespace std;
 
struct Generator {
    struct promise_type {
        int current_value;
        std::suspend_always yield_value(int value) {
            current_value = value;
            return {};
        }
        std::suspend_never initial_suspend() {
            return {};
        }
        std::suspend_never final_suspend() noexcept {
            return {};
        }
        Generator get_return_object() {
            return Generator(coroutine_handle<promise_type>::from_promise(*this));
        }
        void unhandled_exception() {}
    };
    
    Generator(coroutine_handle<promise_type> h) : coro(h) {}
    coroutine_handle<promise_type> coro;
    
    bool next() {
        coro.resume();
        return not coro.done();
    }
 
    int value() {
        return coro.promise().current_value;
    }
 
    ~Generator() {
        coro.destroy();
    }
};
 
Generator fibonacci(int to) {
    int a = 0, b = 1;
    while (a <= to) {
        co_yield a;
        auto tmp = a + b;
        a = b;
        b = tmp;
    }
}
 
int main() {
    Generator gen = fibonacci(10);
    while (gen.next()) {
        cout << gen.value() << " ";
    }
    return 0;
}

Dans l'exemple ci-dessus, nous définissons une structure appelée Generator, qui est également une fonction coroutine. Nous définissons une boucle while dans la fonction coroutine. Chaque fois que le mot-clé co_yield est exécuté, la valeur actuelle de a est renvoyée à l'appelant et les valeurs de a et b sont mises à jour. Dans la fonction principale, nous obtenons un objet Generator en appelant la fonction Generator, puis appelons continuellement sa fonction next() pour obtenir le résultat renvoyé par la fonction coroutine.

Résumé

À travers les exemples ci-dessus, nous pouvons voir que la programmation coroutine peut rendre le programme plus efficace et plus flexible. Dans la vie réelle, la programmation coroutine est largement utilisée dans divers scénarios de programmation simultanée, tels que la programmation réseau, la programmation multithread, etc.

En C++, avec l'aide de la bibliothèque coroutine, nous pouvons implémenter la programmation coroutine plus simplement et plus efficacement. À l’avenir, avec le développement de la technologie informatique et l’amélioration continue du standard C++, la programmation coroutine sera appliquée et promue dans davantage de situations.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn