Question

Je doute que cela puisse être fait de manière portable, mais existe-t-il des solutions? Je pense que cela pourrait être fait en créant une pile alternative, en réinitialisant SP, BP et IP lors de la saisie de la fonction, et en obtenant une sauvegarde de sauvegarde IP et une restauration SP + BP. Les destructeurs et la sécurité des exceptions semblent difficiles mais résolus.

Cela at-il été fait? Est-ce impossible?

Était-ce utile?

La solution

Oui, cela peut être effectué sans problème. Tout ce dont vous avez besoin, c'est d'un petit code d'assemblage pour déplacer la pile d'appels vers une pile allouée sur le tas.

Je voudrais consulter le boost :: coroutine bibliothèque .

La seule chose à surveiller est un débordement de pile. Sur la plupart des systèmes d'exploitation, le dépassement de la pile provoquera un segfault car la page de mémoire virtuelle n'est pas mappée. Cependant, si vous allouez la pile sur le tas, vous n'obtenez aucune garantie. N'oubliez pas cela.

Autres conseils

Sous POSIX, vous pouvez utiliser les routines makecontext () / swapcontext () pour permuter de manière portable les contextes d’exécution. Sous Windows, vous pouvez utiliser l'API fibre. Sinon, vous avez besoin d’un peu de code d’assemblage qui change le contexte de la machine. J'ai implémenté des coroutines à la fois avec ASM (pour AMD64) et avec swapcontext (); ni est très difficile.

Pour la postérité,

Le site Web enchanté de Dmitry Vyukov présente une astuce intelligente en utilisant ucontext et setjump aux coroutines simulées en c ++.

De plus, la bibliothèque de contexte d'Oliver Kowalke a été récemment acceptée dans Boost, alors espérons que nous verrons une version mise à jour de boost.coroutine qui fonctionnera bientôt sur x86_64.

Il n’existe pas de moyen facile de mettre en œuvre la coroutine. Parce que coroutine lui-même est en dehors de l'abstraction de pile de C / C ++, tout comme thread. Il ne peut donc pas être pris en charge sans les modifications de niveau de langue.

Actuellement (C ++ 11), toutes les implémentations de coroutine C ++ existantes sont toutes basées sur le piratage au niveau de l’assemblage, ce qui est difficile à franchir sur les plates-formes. Pour être fiable, il doit être standard et géré par des compilateurs plutôt que par le piratage.

Il existe une proposition standard - N3708 pour cela. Vérifiez si vous êtes intéressé.

Si possible, utilisez un itérateur plutôt qu'une coroutine. De cette façon, vous pouvez continuer à appeler next () pour obtenir la valeur suivante, mais vous pouvez conserver votre état en tant que variables membres au lieu de variables locales.

Cela pourrait rendre les choses plus faciles à maintenir. Un autre développeur C ++ peut ne pas comprendre immédiatement la coroutine, alors qu’il est peut-être plus familiarisé avec un itérateur.

Pour ceux qui souhaitent savoir comment exploiter Coroutines de manière portable en C ++, vous devez disposer de: # 822; o & # 822; u & # 822; & # 822; w & # 822; i & # 822; l & # 822; l & # 822; & # 822; h & # 822; a & # 822; v & # 822; e & # 822; & # 822; t & 822; o & # 822; & # 822; w & # 822; a & # 822; i & # 822; t & # 822; & # 822; f & # 822; o & # 822; r & 822; & C; # 822; + & # 822; + & # 822; 1 & # 822; 7 & # 822; l'attente est terminée (voir ci-dessous)! Le comité de normalisation travaille sur la fonctionnalité voir le l'article N3722 . Pour résumer la version actuelle du document, au lieu de Async et Await, les mots-clés seront résumés et attendent.

Examinez l'implémentation expérimentale de Visual Studio 2015 pour jouer avec l'implémentation expérimentale de Microsoft. Il ne semble pas que clang ait encore une implémentation.

Cppcon discute de la Coroutines sur une abstraction négative pour souligner les avantages de l'utilisation de Coroutines dans C ++ et son impact sur la simplicité et les performances du code.

À l'heure actuelle, nous devons encore utiliser les implémentations de bibliothèque, mais dans un proche avenir, nous aurons des coroutines comme fonctionnalité centrale de C ++.

Mise à jour: On dirait que l'implémentation de coroutine est prévue pour C ++ 20, mais a été publiée en tant que spécification technique avec C ++ 17 ( p0057r2 ). Visual C ++, clang et gcc vous permettent d’accepter l’utilisation d’un indicateur de temps de compilation.

COROUTINE une bibliothèque portable C ++ pour le séquençage de coroutine dans la bonne direction? Cela ressemble à une solution élégante qui a fait ses preuves, il a 9 ans!

Le dossier DOC contient un pdf du document Une bibliothèque C ++ portable pour le séquencement de coroutines de Keld Helsgaun, qui décrit la bibliothèque et fournit de courts exemples l’utilisant.

[mise à jour] En fait, je l’utilise moi-même avec succès. La curiosité a eu raison de moi, alors j’ai cherché dans cette solution et j’ai trouvé que c’était un bon choix pour un problème sur lequel je travaillais depuis quelque temps!

Je ne pense pas qu'il existe de nombreuses implémentations complètes et propres en C ++. Un essai que j'aime bien est la la bibliothèque de protothread d'Adam Dunkels .

Voir aussi Protothreads: simplifier la programmation événementielle de systèmes intégrés à mémoire limitée dans la bibliothèque numérique d'ACM et discussion dans Wikipedia, sujet Protothread ,

Une nouvelle bibliothèque, Boost .Context a été publié aujourd'hui avec des fonctionnalités portables pour la mise en œuvre de coroutines.

Ceci est un vieux fil, mais je voudrais suggérer un piratage utilisant le périphérique de Duff qui ne dépend pas de l'os (pour autant que je m'en souvienne):

Coroutines C utilisant le périphérique de Duff

Et à titre d’exemple, voici une bibliothèque Telnet que j’ai modifiée pour utiliser des coroutines à la place de fork / threads: bibliothèque cli Telnet à l'aide de coroutines

Et comme le standard C antérieur à C99 est essentiellement un véritable sous-ensemble du C ++, cela fonctionne également bien en C ++.

Il est basé sur des macros (cringe), mais le site suivant fournit une implémentation de générateur facile à utiliser: http://www.codeproject.com/KB/cpp/cpp_generators.aspx

J'ai mis au point une implémentation sans code ASM . L'idée est d'utiliser la fonction de création de threads du système pour initialiser la pile et le contexte, et d'utiliser setjmp / longjmp pour changer de contexte. Mais ce n’est pas portable, consultez la version pthread si vous êtes intéressé.

https://github.com/tonbit/coroutine est C ++ 11 single .h implémentation de coroutine asymétrique prenant en charge les primitives curriculum vitae / rendement / attente et le modèle de canal. Il est implémenté via ucontext / fibre, ne dépendant pas de boost, fonctionnant sous linux / windows / macOS. C’est un bon point de départ pour apprendre à mettre en oeuvre la coroutine en c ++.

Découvrez mon implémentation, elle illustre le point de piratage asm et est simple:

https://github.com/user1095108/generic/blob/master /coroutine.hpp

Vous devriez toujours envisager d'utiliser des threads à la place; en particulier dans le matériel moderne. Si vous avez un travail qui peut être séparé logiquement dans des co-routines, l'utilisation de threads signifie que le travail peut en réalité être effectué simultanément, par des unités d'exécution distinctes (cœurs de processeur).

Mais, vous voulez peut-être utiliser des coroutines, peut-être parce que vous avez un algorithme bien testé qui a déjà été écrit et testé de cette façon, ou parce que vous portez du code écrit de cette façon.

Si vous travaillez sous Windows, consultez fibres . Fibers vous fournira un framework de type coroutine avec le support du système d’exploitation.

Je ne connais pas les autres systèmes d'exploitation pour recommander des alternatives.

WvStreams qui implémente des "semi-coroutines" . Celles-ci sont un peu plus faciles à manipuler que des coroutines complètes: vous y appelez, et cela revient à la personne qui l’a appelée.

Il est implémenté en utilisant la WvTask plus flexible, qui supporte les coroutines complètes; vous pouvez le trouver dans la même bibliothèque.

Fonctionne sur Win32 et Linux, au moins, et probablement sur tout autre système Unix.

J'ai moi-même essayé d'implémenter des coroutines à l'aide de C ++ 11 et de threads:

#include <iostream>
#include <thread>

class InterruptedException : public std::exception {
};

class AsyncThread {
public:
    AsyncThread() {
        std::unique_lock<std::mutex> lock(mutex);
        thread.reset(new std::thread(std::bind(&AsyncThread::run, this)));
        conditionVar.wait(lock); // wait for the thread to start
    }
    ~AsyncThread() {
        {
            std::lock_guard<std::mutex> _(mutex);
            quit = true;
        }
        conditionVar.notify_all();
        thread->join();
    }
    void run() {
        try {
            yield();
            for (int i = 0; i < 7; ++i) {
                std::cout << i << std::endl;
                yield();
            }
        } catch (InterruptedException& e) {
            return;
        }
        std::lock_guard<std::mutex> lock(mutex);
        quit = true;
        conditionVar.notify_all();
    }
    void yield() {
        std::unique_lock<std::mutex> lock(mutex);
        conditionVar.notify_all();
        conditionVar.wait(lock);
        if (quit) {
            throw InterruptedException();
        }
    }
    void step() {
        std::unique_lock<std::mutex> lock(mutex);
        if (!quit) {
            conditionVar.notify_all();
            conditionVar.wait(lock);
        }
    }
private:
    std::unique_ptr<std::thread> thread;
    std::condition_variable conditionVar;
    std::mutex mutex;
    bool quit = false;
};

int main() {
    AsyncThread asyncThread;
    for (int i = 0; i < 3; ++i) {
        std::cout << "main: " << i << std::endl;
        asyncThread.step();
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top