Maison >développement back-end >C++ >Comment maintenir le séquencement des tâches avec la réentrée dans les opérations asynchrones ?

Comment maintenir le séquencement des tâches avec la réentrée dans les opérations asynchrones ?

Susan Sarandon
Susan Sarandonoriginal
2024-12-28 17:02:15870parcourir

How Can Task Sequencing Be Maintained with Re-Entrancy in Asynchronous Operations?

Séquencement des tâches et réentrée

Dans les scénarios où les tâches peuvent arriver plus rapidement qu'elles ne sont traitées et peuvent dépendre des résultats antérieurs, le séquençage des tâches devient crucial. Ce défi est aggravé lorsqu'une réentrée est requise.

Énoncé du problème

Un gestionnaire de commandes d'interface utilisateur peut traiter les commandes de manière synchrone ou asynchrone. Les commandes peuvent arriver à un rythme qui dépasse la vitesse de traitement, ce qui nécessite une mise en file d'attente et un traitement séquentiel. Le résultat de chaque nouvelle tâche peut dépendre de son prédécesseur. Bien que l'annulation soit exclue par souci de simplicité, la réentrée doit être prise en charge.

Approche initiale

Dans une application console de base, une classe AsyncOp gère le séquençage des tâches. Chaque tâche est traitée comme une continuation de la précédente, garantissant que les dépendances sont respectées. Cependant, lorsque la réentrée est introduite, la logique s'effondre.

Solution synchronisée

Pour résoudre ce problème, les tâches sont construites manuellement sans les planifier initialement. Au lieu de cela, « Task.Factory.StartNew » est utilisé pour exécuter les tâches de manière synchrone, les empêchant de s'exécuter jusqu'à ce que la tâche wrapper soit prête. Cela garantit que la séquence est maintenue.

Mise en œuvre du code

class AsyncOp<T>
{
    Task<T> _pending = Task.FromResult(default(T));

    public Task<T> CurrentTask => _pending;

    public Task<T> RunAsync(Func<Task<T>> handler, bool useSynchronizationContext = false)
    {
        var pending = _pending;
        var wrapper = async () =>
        {
            var prevResult = await pending;
            Console.WriteLine($"\nprev task result:  {prevResult}");
            return await handler();
        };

        var task = new Task<Task<T>>(wrapper);
        var inner = task.Unwrap();
        _pending = inner;

        task.RunSynchronously(useSynchronizationContext ?
            TaskScheduler.FromCurrentSynchronizationContext() :
            TaskScheduler.Current);

        return inner;
    }
}

Sortie mise à jour

Test #1...

prev task result:  0
this task arg: 1000

prev task result:  1000
this task arg: 900

prev task result:  900
this task arg: 800

Press any key to continue to test #2...


prev task result:  800
this task arg: 100

prev task result:  100
this task arg: 200

Extensions

Cette approche permet des améliorations supplémentaires telles que la sécurité des threads en implémentant un verrou sur protéger l’État partagé. De plus, une logique d'annulation/redémarrage peut être intégrée pour gérer les interruptions de tâches.

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