Namespaces
Variants

Execution control library (since C++26)

From cppreference.net

La bibliothèque de contrôle d'exécution fournit un cadre pour gérer l'exécution asynchrone sur des ressources d'exécution génériques.

La bibliothèque vise à fournir des types de vocabulaire pour les opérations asynchrones et à permettre la construction de graphes d'exécution de tâches de manière simple et composable.

Table des matières

Définitions générales de la bibliothèque

  • Sender : Une description de travail asynchrone à envoyer pour exécution. Produit un état d'opération (ci-dessous).
  • Les expéditeurs « envoient » de manière asynchrone leurs résultats aux écouteurs appelés « récepteurs » (ci-dessous).
  • Les expéditeurs peuvent être composés en graphes de tâches en utilisant des algorithmes génériques.
  • Les fabriques d'expéditeurs et les adaptateurs sont des algorithmes génériques qui capturent les modèles asynchrones courants dans les objets satisfaisant le concept sender .
  • Receiver : Un rappel généralisé qui consomme ou « reçoit » les résultats asynchrones produits par un expéditeur.
  • Les récepteurs disposent de trois « canaux » différents par lesquels un émetteur peut propager les résultats : succès, échec et annulé, dénommés respectivement « valeur », « erreur » et « arrêté ».
  • Les récepteurs fournissent un environnement d'exécution extensible : un ensemble de paires clé/valeur que le consommateur peut utiliser pour paramétrer l'opération asynchrone.
  • État de l'opération : Un objet qui contient l'état requis par l'opération asynchrone.
  • Un émetteur et un récepteur sont connectés lorsqu'ils sont passés à la std::execution::connect fonction.
  • Le résultat de la connexion d'un émetteur et d'un récepteur est un état d'opération.
  • Le travail n'est pas mis en file d'attente pour exécution avant que « start » ne soit appelé sur un état d'opération.
  • Une fois démarré, la durée de vie de l'état d'opération ne peut pas se terminer avant que l'opération asynchrone ne soit complète, et son adresse doit être stable.
  • Scheduler : Un gestionnaire léger d'un contexte d'exécution.
  • Un contexte d'exécution est une source d'exécution asynchrone telle qu'un pool de threads ou un flux GPU.
  • Un planificateur est une fabrique pour un expéditeur qui complète son récepteur à partir d'un thread d'exécution appartenant au contexte d'exécution.

Utilitaires de bibliothèque

Concepts

Planificateurs

Défini dans l'en-tête <execution>
Défini dans l'espace de noms std::execution
spécifie qu'un type est un scheduler
(concept)

Émetteurs

Défini dans l'en-tête <execution>
Défini dans l'espace de noms std::execution
spécifie qu'un type est un sender
(concept)
spécifie un sender qui peut créer des opérations asynchrones pour un type d'environnement associé donné
(concept)
spécifie un sender qui peut se connecter avec un type de receiver spécifique
(concept)

Récepteurs

Défini dans l'en-tête <execution>
Défini dans l'espace de noms std::execution
spécifie qu'un type est un receiver
(concept)
spécifie qu'un type est un receiver pour des signatures d'achèvement données
(concept)

États d'opération

Défini dans l'en-tête <execution>
Défini dans l'espace de noms std::execution
spécifie qu'un type est un état d'opération
(concept)

Composants utilitaires

Contextes d'exécution

Défini dans l'en-tête <execution>
Défini dans l'espace de noms std::execution
ressource d'exécution contenant une file d'attente de tâches MPSC thread-safe et une boucle d'événements à commande manuelle
(classe)

Domaines d'exécution

Défini dans l'en-tête <execution>
Défini dans l'espace de noms std::execution
type d'étiquette de domaine d'exécution par défaut qui distribue les transformations depuis une étiquette d'émetteur
(classe)
transforme en un nouvel émetteur sous une étiquette de domaine d'exécution donnée
(modèle de fonction)
transforme en un nouvel objet interrogeable sous une étiquette de domaine d'exécution donnée
(modèle de fonction)
consomme un émetteur en utilisant une étiquette de consommateur d'émetteur donnée avec un ensemble d'arguments et retourne son résultat sous une étiquette de domaine d'exécution donnée
(modèle de fonction)

Garantie de progression

Défini dans l'en-tête <execution>
Défini dans l'espace de noms std::execution
spécifie une garantie de progression forward des agents d'exécution créés par la ressource d'exécution associée au planificateur
(énumération)

Environnements

Défini dans l'en-tête <execution>
Défini dans l'espace de noms std::execution
construit un objet interrogeable à partir d'un objet de requête et d'une valeur
(modèle de classe)
agrège plusieurs objets interrogeables en un seul objet interrogeable
(modèle de classe)
retourne l'objet interrogeable associé pour son argument donné
(objet de point de personnalisation)

Requêtes

Défini dans l'en-tête <execution>
demande à un objet de requête s'il doit être transmis via des adaptateurs interrogeables
(objet point de personnalisation)
demande à un objet interrogeable son allocateur associé
(objet point de personnalisation)
demande à un objet interrogeable son jeton d'arrêt associé
(objet point de personnalisation)
demande à un objet interrogeable son étiquette de domaine d'exécution associée
(objet point de personnalisation)
demande à un objet interrogeable son ordonnanceur associé
(objet point de personnalisation)
demande à un objet interrogeable un ordonnanceur pouvant être utilisé pour déléguer du travail dans le but d'une délégation de progression
(objet point de personnalisation)
obtient l'ordonnanceur de complétion associé à une étiquette de complétion depuis les attributs d'un émetteur
(objet point de personnalisation)
demande à un ordonnanceur sa execution::forward_progress_guarantee
(objet point de personnalisation)

Signatures de complétion

Défini dans l'en-tête <execution>
Défini dans l'espace de noms std::execution
type qui encode un ensemble de signatures de complétion
(modèle de classe)
obtient les signatures de complétion d'un expéditeur
(objet de point de personnalisation)
transforme un ensemble de signatures de complétion en un autre
(alias de modèle)
transforme les signatures de complétion d'un expéditeur
(alias de modèle)
obtient le type de tag d'un expéditeur
(alias de modèle)
obtient le type de complétion de valeur d'un expéditeur
(alias de modèle)
obtient le type de complétion d'erreur d'un expéditeur
(alias de modèle)
détermine si l'expéditeur prend en charge la complétion d'arrêt
(variable de modèle)

Utilitaire de coroutine

Défini dans l'en-tête <execution>
Défini dans l'espace de noms std::execution
transforme une expression en objet awaitable dans une coroutine particulière
(objet de point de personnalisation)
lorsqu'utilisé comme classe de base d'un type de promesse de coroutine, permet aux senders d'être awaitable dans ce type de coroutine
(modèle de classe)

Opérations principales

État de fonctionnement

Défini dans l'en-tête <execution>
Défini dans l'espace de noms std::execution
connecte un sender avec un receiver
(point de personnalisation)
démarre l'opération asynchrone associée à un objet operation_state
(point de personnalisation)

Fonctions d'achèvement

Ces fonctions sont appelées par les expéditeurs pour annoncer l'achèvement du travail à leurs destinataires.

Défini dans l'en-tête <execution>
Défini dans l'espace de noms std::execution
fonction d'achèvement de valeur indiquant une terminaison réussie
(objet de point de personnalisation)
fonction d'achèvement d'erreur indiquant qu'une erreur s'est produite pendant le calcul ou la planification
(objet de point de personnalisation)
fonction d'achèvement d'arrêt indiquant qu'une opération s'est terminée avant de pouvoir atteindre le succès ou l'échec
(objet de point de personnalisation)

Algorithmes de l'émetteur

Fabriques d'expéditeurs

Une fabrique d'expéditeur est une fonction qui retourne un expéditeur et dont les paramètres ont des types pour lesquels le concept sender est false .

Les éléments suivants sont des fabriques d'expéditeur :

Défini dans l'en-tête <execution>
Défini dans l'espace de noms std::execution
Accepte un nombre variable d'arguments et retourne un expéditeur qui, lorsqu'il est connecté et démarré, se termine de manière synchrone en passant les arguments à la fonction d'achèvement de valeur du récepteur
(objet de point de personnalisation)
Accepte un seul argument et retourne un expéditeur qui, lorsqu'il est connecté et démarré, se termine de manière synchrone en passant l'argument à la fonction d'achèvement d'erreur du récepteur
(objet de point de personnalisation)
crée un expéditeur qui se termine immédiatement en appelant la fonction set_stopped de son récepteur
(objet de point de personnalisation)
crée un expéditeur qui interroge l'environnement associé à son récepteur
(objet de point de personnalisation)
prépare un graphe de tâches pour l'exécution sur un ordonnanceur donné
(objet de point de personnalisation)

Adaptateurs d'émetteurs canalizables

Défini dans l'en-tête <execution>
Défini dans l'espace de noms std::execution
classe de base utilitaire pour définir un objet de fermeture d'adaptateur d'émetteur pouvant être utilisé avec l'opérateur pipe
(modèle de classe)

Adaptateurs d'émetteur

Un adaptateur d'émetteur est une fonction retournant un émetteur dont les paramètres incluent au moins un dont le type satisfait le sender concept, et pour lequel l'émetteur retourné est un émetteur parent des arguments émetteurs de la fonction adaptateur.

Les éléments suivants sont des adaptateurs d'émetteur :

Défini dans l'en-tête <execution>
Défini dans l'espace de noms std::execution
adapte un émetteur fourni en un émetteur qui démarrera une exécution sur la ressource d'exécution du planificateur fourni
(objet de point de personnalisation)
adapte un expéditeur fourni en un qui se termine sur la ressource d'exécution du planificateur fourni
(objet de point de personnalisation)
adapte un émetteur fourni pour transférer l'exécution vers la ressource d'exécution d'un ordonnanceur fourni sur laquelle l'émetteur ou la continuation s'exécute, puis retransfère l'exécution vers la ressource d'origine
(objet de point de personnalisation)
planifie le travail dépendant de l'achèvement d'un émetteur fourni sur la ressource d'exécution d'un planificateur fourni
(objet de point de personnalisation)
chaîne le graphe de tâches de l'émetteur d'entrée avec un nœud représentant l'invocation de la fonction fournie avec les valeurs envoyées par l'émetteur d'entrée comme arguments
(objet de point de personnalisation)
chaîne le graphe de tâches à partir de l'émetteur d'entrée avec un nœud représentant l'appel de la fonction fournie avec l'erreur envoyée par l'émetteur d'entrée si une erreur s'est produite
(objet de point de personnalisation)
chaîne le graphe de tâches de l'émetteur d'entrée avec un nœud représentant l'appel de la fonction fournie avec le comportement d'arrêt de l'émetteur d'entrée si un signal "stopped" est envoyé
(objet de point de personnalisation)
renvoie un expéditeur qui représente un nœud enchaîné à l'expéditeur d'entrée, qui, lorsqu'il est démarré, invoque la fonction fournie avec les valeurs envoyées par l'expéditeur d'entrée comme arguments
(point de personnalisation d'objet)
retourne un expéditeur qui représente un nœud enchaîné à l'expéditeur d'entrée, qui invoque la fonction fournie avec l'erreur de l'expéditeur d'entrée, si elle s'est produite
(objet de point de personnalisation)
retourne un expéditeur qui représente un nœud enchaîné à l'expéditeur d'entrée, qui invoque la fonction fournie avec le jeton d'arrêt de l'expéditeur d'entrée, si le signal "arrêté" est envoyé
(objet de point de personnalisation)
crée un émetteur multi-tir qui invoque la fonction avec chaque index dans la forme fournie ainsi que les valeurs envoyées par l'émetteur d'entrée. L'émetteur se termine une fois que toutes les invocations sont terminées, ou qu'une erreur s'est produite
(objet de point de personnalisation)
si l'émetteur fourni est un émetteur multi-tir, retourne cet émetteur, sinon, retourne un émetteur multi-tir qui émet des valeurs équivalentes aux valeurs émises par l'émetteur fourni
(objet de point de personnalisation)
adapte plusieurs émetteurs d'entrée en un émetteur qui se termine une fois que tous les émetteurs d'entrée ont terminé
(objet de point de personnalisation)
adapte plusieurs émetteurs d'entrée, chacun pouvant avoir plusieurs signatures d'achèvement, en un émetteur qui se termine une fois que tous les émetteurs d'entrée ont terminé
(objet de point de personnalisation)
retourne un expéditeur qui envoie une variante de tuples de tous les ensembles possibles de types envoyés par l'expéditeur d'entrée
(objet de point de personnalisation)
retourne un expéditeur qui mappe le canal de valeur vers std:: optional < std:: decay_t < T >> et le canal arrêté vers std:: nullopt
(objet de point de personnalisation)
retourne un expéditeur qui mappe le canal arrêté vers une erreur
(point de personnalisation d'objet)

Consommateurs de l'émetteur

Un consommateur émetteur est un algorithme qui prend un ou plusieurs émetteurs en paramètres et qui ne retourne pas d'émetteur.

Défini dans l'en-tête <execution>
Défini dans l'espace de noms std::this_thread
bloque le thread courant jusqu'à ce que l'émetteur spécifié se termine et retourne son résultat asynchrone
(objet de point de personnalisation)
bloque le thread courant jusqu'à ce que l'émetteur spécifié avec potentiellement plusieurs signatures d'achèvement se termine et retourne son résultat asynchrone
(objet de point de personnalisation)

Exemple

Une version de cet exemple est disponible sur godbolt.org , où elle utilise stdexec , une implémentation de référence expérimentale de std::execution .

#include <cstdio>
#include <execution>
#include <string>
#include <thread>
#include <utility>
using namespace std::literals;
int main()
{
    std::execution::run_loop loop;
    std::jthread worker([&](std::stop_token st)
    {
        std::stop_callback cb{st, [&]{ loop.finish(); }};
        loop.run();
    });
    std::execution::sender auto hello = std::execution::just("hello world"s);
    std::execution::sender auto print
        = std::move(hello)
        | std::execution::then([](std::string msg)
        {
            return std::puts(msg.c_str());
        });
    std::execution::scheduler auto io_thread = loop.get_scheduler();
    std::execution::sender auto work = std::execution::on(io_thread, std::move(print));
    auto [result] = std::this_thread::sync_wait(std::move(work)).value();
    return result;
}

Sortie :

hello world

Voir aussi

(C++11)
exécute une fonction de manière asynchrone (potentiellement dans un nouveau thread) et retourne une std::future qui contiendra le résultat
(modèle de fonction)