for compile c++ coroutine c++1z

compile - ¿Cómo implementa Coroutines en C++?



llvm 3.7 1 (17)

Dudo que se pueda hacer de forma portátil, pero ¿hay alguna solución por ahí? Creo que se podría hacer creando una pila alternativa y reiniciando SP, BP e IP en la entrada de la función, y teniendo rendimiento guardar IP y restaurar SP + BP. Destructores y seguridad de excepción parecen complicados pero solucionables.

Ha sido hecho? ¿Es imposible?


¿ COROUTINE una biblioteca portátil de C ++ para la secuenciación de corrutinas te señala en la dirección correcta? Parece una solución elegante que ha durado la prueba del tiempo ... ¡tiene 9 años!

En la carpeta DOC hay un pdf del documento Una biblioteca portátil de C ++ para Coroutine Sequencing, de Keld Helsgaun, que describe la biblioteca y proporciona ejemplos cortos para usarla.

[actualización] En realidad estoy haciendo un uso exitoso de él mismo. Curiosity se apoderó de mí, así que investigué esta solución y descubrí que encajaba bien con un problema en el que llevaba tiempo trabajando.


En POSIX, puede usar las rutinas makecontext () / swapcontext () para cambiar de forma portátil los contextos de ejecución. En Windows, puede usar la API de fibra. De lo contrario, todo lo que necesita es un poco de código ensamblador de pegamento que cambia el contexto de la máquina. He implementado corutinas tanto con ASM (para AMD64) como con swapcontext (); ninguno es muy difícil.



Este es un hilo viejo, pero me gustaría sugerir un truco usando el dispositivo de Duff que no depende del os (por lo que recuerdo):

C coroutines usando el dispositivo de Duff

Y como ejemplo, aquí hay una biblioteca telnet que modifiqué para usar corutinas en lugar de fork / threads: biblioteca Telnet cli usando corutinas

Y dado que el estándar C anterior a C99 es esencialmente un verdadero subconjunto de C ++, esto también funciona bien en C ++.


He encontrado una implementación sin código asm . La idea es utilizar la función de creación de hilos del sistema para inicializar la pila y el contexto, y usar setjmp / longjmp para cambiar el contexto. Pero no es portátil, consulte la versión engañosa de pthread si está interesado.


He intentado implementar coroutines usando C ++ 11 y 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(); } }


No creo que haya muchas implementaciones completas y limpias en C ++. Una prueba que me gusta es la biblioteca protothread .


No hay una manera fácil de implementar coroutine. Porque la coroutine en sí está fuera de la abstracción de pila de C / C ++ al igual que el hilo. Por lo tanto, no se puede admitir sin cambios de nivel de idioma para admitir.

Actualmente (C ++ 11), todas las implementaciones de coronas en C ++ existentes se basan en la piratería a nivel de ensamblado, lo cual es difícil de ser seguro y confiable al cruzar plataformas. Para ser confiable necesita ser estándar, y manejado por compiladores en lugar de piratear.

Hay una propuesta estándar: N3708 para esto. Compruébalo si estás interesado.


Para aquellos que quieran saber cómo pueden aprovechar Coroutines de forma portátil en C ++, tendrán que esperar C ++ 17. El comité de estándares está trabajando en la característica, vea el documento N3722 . Para resumir el borrador actual del documento, en lugar de Async y Await, las palabras clave serán reanudables y aguardarán.

Eche un vistazo a la implementación experimental en Visual Studio 2015 para jugar con la implementación experimental de Microsoft. No parece que clang tenga una implementación todavía.

Existe una buena charla de Cppcon Coroutines, una abstracción general negativa que resume los beneficios de usar Coroutines en C ++ y cómo afecta la simplicidad y el rendimiento del código.

En la actualidad, todavía tenemos que usar implementaciones de bibliotecas, pero en el futuro cercano, tendremos coroutines como característica central de C ++.

Actualización: Parece que la implementación de coroutine no está convirtiéndose en C ++ 17, pero será una especificación técnica ( p0057r2 ). Por el lado positivo, parece que es compatible con la bandera de -futuristas_ts y en la actualización 2 de Visual Studio 2015. Las palabras clave también tienen una co_ precedida por ellas. Entonces co_await, co_yield, etc.


Para la posteridad,

El maravilloso sitio web de Dmitry Vyukov tiene un ingenioso truco usando ucontext y setjump para corutinas simuladas en c ++.

Además, la biblioteca de contexto de Oliver Kowalke fue recientemente aceptada en Boost, así que espero que veamos una versión actualizada de boost.coroutine que funcione pronto en x86_64.


Puede ser mejor con un iterador que una corutina si es posible. De esta forma, puede seguir llamando a next() para obtener el siguiente valor, pero puede mantener su estado como variables miembro en lugar de variables locales.

Podría hacer las cosas más sostenibles. Es posible que otro desarrollador de C ++ no comprenda inmediatamente la corutina, mientras que podría estar más familiarizado con un iterador.


Sí, se puede hacer sin ningún problema. Todo lo que necesita es un pequeño código de ensamblaje para mover la pila de llamadas a una pila recién asignada en el montón.

Me gustaría ver la biblioteca boost :: coroutine .

Lo único que debes tener en cuenta es un desbordamiento de pila. En la mayoría de los sistemas operativos que se desbordan, la pila provocará una segfault porque la página de memoria virtual no está asignada. Sin embargo, si asigna la pila en el montón, no obtiene ninguna garantía. Solo ten eso en cuenta.


Siempre debe considerar usar hilos en su lugar; especialmente en hardware moderno. Si tiene un trabajo que puede separarse lógicamente en Co-rutinas, el uso de hilos significa que el trabajo podría hacerse de manera simultánea, por unidades de ejecución separadas (núcleos de procesador).

Pero, tal vez quieras usar corutinas, quizás porque tienes un algoritmo bien probado que ya se ha escrito y probado de esa manera, o porque estás portando código escrito de esa manera.

Si trabajas dentro de Windows, deberías echarle un vistazo a las fibras . Fibras le proporcionará un marco similar a corutina con soporte del sistema operativo.

No estoy familiarizado con otros sistemas operativos para recomendar alternativas allí.


Una nueva biblioteca, Boost.Context , se lanzó hoy con funciones portátiles para implementar coroutines.



WvCont es una parte de WvStreams que implementa las denominadas semi-corutinas. Estos son un poco más fáciles de manejar que las coroutinas completas: lo llamas y se rinde a la persona que lo llamó.

Se implementa utilizando el WvTask más flexible, que admite coroutines completas; puedes encontrarlo en la misma biblioteca.

Funciona en win32 y Linux, al menos, y probablemente en cualquier otro sistema Unix.


https://github.com/tonbit/coroutine es C ++ 11 implementación de corneta asimétrica única .h que admite primitivas de reanudación / rendimiento / espera y modelo de canal. Está implementando a través de ucontext / fiber, sin depender de boost, ejecutándose en linux / windows / macOS. Es un buen punto de partida para aprender a implementar coroutine en c ++.