Jak zaimplementować Coroutines w C++

Wątpię, że da się to zrobić przenośnie, ale czy są jakieś rozwiązania? Myślę, że można to zrobić, tworząc alternatywny stos i resetując SP, BP i IP przy wpisie funkcji, i mając wydajność Zapisz IP i przywróć SP+BP. Destruktory i bezpieczeństwo WYJĄTKÓW wydają się trudne, ale rozwiązywalne.

Czy to już zrobione? Czy to niemożliwe?

Author: Atifm, 2008-09-23

17 answers

Tak to można zrobić bez problemu. Wszystko czego potrzebujesz to mały kod asemblera, aby przenieść stos wywołań do nowo przydzielonego stosu na stercie.

Chciałbym spojrzeć na boost:: coroutine biblioteka.

Jedyną rzeczą, na którą powinieneś uważać, jest przepełnienie stosu. W większości systemów operacyjnych przepełnienie stosu spowoduje segfault, ponieważ strona pamięci wirtualnej nie jest mapowana. Jeśli jednak przydzielisz stos na stertę, nie otrzymasz żadnej gwarancji. Pamiętaj o tym.

 87
Author: Ted,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-29 20:04:00

W POSIX, możesz użyć funkcji makecontext()/swapcontext (), aby przenośnie przełączać konteksty wykonania. W systemie Windows można użyć fiber API. W przeciwnym razie wystarczy trochę kodu kleju, który przełącza kontekst maszyny. Zaimplementowałem coroutiny zarówno z ASM (dla AMD64), jak i ze swapcontext (); żadna z nich nie jest bardzo trudna.

 18
Author: zvrba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-23 16:05:46

Dla potomności,

Dmitry Vyukov ' s wondeful web site ma sprytny trick za pomocą ucontext i setjump do symulowanych coroutines w c++.

Również biblioteka kontekstowa Olivera Kowalke została Ostatnio przyjęta do Boost, więc miejmy nadzieję, że zobaczymy zaktualizowaną wersję boost.coroutine, który wkrótce będzie działał na x86_64.

 14
Author: tgoodhart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-24 22:22:41

Nie ma łatwego sposobu na wdrożenie coroutine. Ponieważ samo coroutine jest poza abstrakcją stosu C / C++, tak jak thread. Więc nie może być obsługiwany bez zmiany poziomu języka do obsługi.

Obecnie (C++11), wszystkie istniejące implementacje C++ coroutine są oparte na hakowaniu na poziomie assembly, które jest trudne do bezpiecznego i niezawodnego przejścia przez platformy. Aby być niezawodnym, musi być standardowy i obsługiwany przez kompilatory, a nie przez hakerów.

Istnieje standard propozycja-N3708 do tego. Sprawdź, jeśli jesteś zainteresowany.

 10
Author: Eonil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-30 02:41:28

Może być lepiej z iteratorem niż koroutine, jeśli to możliwe. W ten sposób możesz nadal wywoływać next(), aby uzyskać następną wartość, ale możesz zachować swój stan jako zmienne członkowskie zamiast zmiennych lokalnych.

To może sprawić, że rzeczy będą łatwiejsze do utrzymania. Inny programista C++ może nie od razu zrozumieć coroutine, podczas gdy może być bardziej zaznajomiony z iteratorem.
 7
Author: Steve g,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-03 23:36:38

Myślę, że nie ma wielu pełnowymiarowych, czystych implementacji w C++. Jedna próba, która mi się podoba, to protothread library .

 5
Author: yrp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-23 15:37:26

Czy COROUTINE przenośna biblioteka C++ do sekwencjonowania coroutine wskazuje ci właściwy kierunek? Wydaje się eleganckim rozwiązaniem, które przetrwało próbę time.....it ma 9 lat!

W folderze DOC znajduje się pdf z papieru Przenośna biblioteka C++ do sekwencjonowania Coroutine przez Kelda Helsgauna, która opisuje bibliotekę i dostarcza krótkich przykładów z jej użycia.

[update] sam z tego korzystam. Ciekawość mnie ogarnęła, więc spojrzałem do tego rozwiązania i okazało się, że jest to dobre dopasowanie do problemu, nad którym pracuję od jakiegoś czasu!

 5
Author: Dan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-20 21:36:57

Dla tych, którzy chcą wiedzieć, jak mogą korzystać z Corutines w przenośny sposób w C++ trzeba będzie poczekać na C++17. Komitet Normalizacyjny pracuje nad tą cechą Patrz n3722 papier . Aby podsumować bieżący szkic artykułu, zamiast Asynchronizacji i oczekiwania, słowa kluczowe będą wznawiane i czekają.

Przyjrzyj się eksperymentalnej implementacji w Visual Studio 2015, aby pobawić się eksperymentalną implementacją Microsoftu. Nie wygląda na to, że clang ma wdrożenie jeszcze.

Jest dobra rozmowa z Cppcon Coroutines a negative overhead abstraction zarys korzyści płynących z używania Coroutines w C++ i jak wpływa to na prostotę i wydajność kodu.

Obecnie nadal musimy korzystać z implementacji bibliotek, ale w niedalekiej przyszłości będziemy mieli coroutines jako podstawową funkcję C++.

Update: Wygląda na to, że implementacja coroutine nie wchodzi do C++17, ale będzie to specyfikacja techniczna (p0057r2). Na plusie wygląda na to, że ich wsparcie jest w clang z flagą-fcoroutines_ts i w aktualizacji Visual Studio 2015 2. Słowa kluczowe mają również poprzedzony co_. Więc co_await, co_yield itp.

 5
Author: Atifm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-22 18:47:28

Nowa biblioteka, Boost.Kontekst, został wydany dzisiaj z przenośnymi funkcjami do wdrażania coroutines.

 3
Author: Jeff Trull,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-30 02:12:53

To jest stary wątek, ale chciałbym zaproponować hack przy użyciu urządzenia Duffa, które nie jest zależne od systemu operacyjnego (o ile pamiętam):

C coroutines using Duff ' s device

I jako przykład, tutaj jest biblioteka telnet, którą zmodyfikowałem, aby używać coroutines zamiast fork/threads: Biblioteka Telnet CLI przy użyciu coroutines

A ponieważ standard C poprzedzający C99 jest zasadniczo prawdziwym podzbiorem C++, działa to również w C++.

 3
Author: Erik Alapää,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-04 15:48:31

Jest oparty na (cringe) makrach, ale następująca strona zapewnia łatwą w użyciu implementację generatora: http://www.codeproject.com/KB/cpp/cpp_generators.aspx

 2
Author: Mark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-04 13:31:09

Wymyśliłem implementację bez kodu asm. Ideą jest użycie systemowej funkcji tworzenia wątków do inicjalizacji stosu i kontekstu oraz użycie setjmp/longjmp do przełączania kontekstu. Ale nie jest przenośny, Zobacz tricky pthread wersja Jeśli jesteś zainteresowany.

 2
Author: rox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-14 03:34:46

Https://github.com/tonbit/coroutine to C++11 single .h asymetryczna implementacja coroutine wspierająca CV/yield/wait primitives i model kanału. Jest implementowany przez ucontext / fiber, a nie w zależności od boost, działa na Linuksie / windows / macOS. Jest to dobry punkt wyjścia do nauki implementacji coroutine w c++.

 1
Author: atto_mu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-16 01:58:34

Sprawdź moją implementację, ilustruje ona punkt hakowania asm i jest prosta:

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

 1
Author: user1095108,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-05 08:29:42

Powinieneś zawsze rozważyć użycie wątków; szczególnie w nowoczesnym sprzęcie. Jeśli masz pracę, która może być logicznie rozdzielona w Ko-procedurach, użycie wątków oznacza, że praca może być wykonywana jednocześnie, przez oddzielne jednostki wykonawcze (rdzenie procesora).

Ale, być może chcesz używać coroutines, być może dlatego, że masz dobrze przetestowany algorytm, który został już napisany i przetestowany w ten sposób, lub dlatego, że portujesz kod napisany w ten sposób.

Jeśli pracujesz w systemie Windows należy spojrzeć na włókna . Fibers da ci Framework podobny do coroutine z obsługą systemu operacyjnego.

Nie jestem zaznajomiony z innymi systemami operacyjnymi, aby polecać tam alternatywy.

 0
Author: Euro Micelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-23 15:58:51

Wvcont jest częścią WvStreams, która implementuje tak zwane półkoutiny. Są nieco łatwiejsze w obsłudze niż pełne korutynki: wzywasz do tego, a to ustępuje osobie, która go nazwała.

Jest zaimplementowany przy użyciu bardziej elastycznego WvTask, który obsługuje pełne coroutines; można go znaleźć w tej samej bibliotece.

Działa przynajmniej na win32 i Linuksie, i prawdopodobnie na każdym innym systemie uniksowym.

 0
Author: apenwarr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-23 19:28:55

Sam próbowałem zaimplementować coroutines używając C++11 i 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();
    }
}
 -2
Author: jhasse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-27 18:10:55