Coroutine

Coroutines are computer program components that allow execution to be suspended and resumed, generalizing subroutines for cooperative multitasking.

Coroutines are well-suited for implementing familiar program components such as cooperative tasks, exceptions, event loops, iterators, infinite lists and pipes.

Although this example is often used as an introduction to multithreading, two threads are not needed for this: the yield statement can be implemented by a jump directly from one routine into the other.

It is possible to implement coroutines using preemptively-scheduled threads, in a way that will be transparent to the calling code, but some of the advantages (particularly the suitability for hard-realtime operation and relative cheapness of switching between them) will be lost.

Specifically, while both can yield multiple times, suspending their execution and allowing re-entry at multiple entry points, they differ in coroutines' ability to control where execution continues immediately after they yield, while generators cannot, instead transferring control back to the generator's caller.

Using coroutines for state machines or concurrency is similar to using mutual recursion with tail calls, as in both cases the control changes to a different one of a set of routines.

Since coroutines yield rather than return, and then resume execution rather than restarting from the beginning, they are able to hold state, both variables (as in a closure) and execution point, and yields are not limited to being in tail position; mutually recursive subroutines must either use shared variables or pass state as parameters.

Threads, and to a lesser extent fibers, are an alternative to coroutines in mainstream programming environments today.

Threads provide facilities for managing the real-time cooperative interaction of simultaneously executing pieces of code.

In order to implement general-purpose coroutines, a second call stack must be obtained, which is a feature not directly supported by the C language.

A reliable (albeit platform-specific) way to achieve this is to use a small amount of inline assembly to explicitly manipulate the stack pointer during initial creation of the coroutine.

[27] Once a second call stack has been obtained with one of the methods listed above, the setjmp and longjmp functions in the standard C library can then be used to implement the switches between coroutines.

Minimalist implementations, which do not piggyback off the setjmp and longjmp functions, may achieve the same result via a small block of inline assembly which swaps merely the stack pointer and program counter, and clobbers all other registers.

Due to the lack of direct language support, many authors have written their own libraries for coroutines which hide the above details.

Other notable implementations include libpcl,[29] coro,[30] lthread,[31] libCoroutine,[32] libconcurrency,[33] libcoro,[34] ribs2,[35] libdill.,[36] libaco,[37] and libco.

[26] In addition to the general approach above, several attempts have been made to approximate coroutines in C with combinations of subroutines and macros.

Simon Tatham's contribution,[38] based on Duff's device, is a notable example of the genre, and is the basis for Protothreads and similar implementations.

[39] In addition to Duff's objections,[24] Tatham's own comments provide a frank evaluation of the limitations of this approach: "As far as I know, this is the worst piece of C hackery ever seen in serious production code.

During the development of the .NET Framework 2.0, Microsoft extended the design of the Common Language Runtime (CLR) hosting APIs to handle fiber-based scheduling with an eye towards its use in fiber-mode for SQL server.

[60] These coroutines provide concurrency without parallelism, and are scheduled preemptively on a single operating system thread.

Since, in most Smalltalk environments, the execution stack is a first-class citizen, coroutines can be implemented without additional library or VM support.

They are designed to be used with a Gtk Main Loop, but can be used alone if care is taken to ensure that the end callback will never have to be called before doing, at least, one yield.