Erlang, Go, Lua, and Scheme get this right. Stackless Python never caught on :( But Java may get proper stackful coroutines in the near future.
[1] Stackless coroutines, which means you can't yield across nested function invocations. The unfortunately named Stackless Python actually implements stackful coroutines. "Stackless" in Stackless Python refers to not implementing the Python call stack on the C ABI stack. Stackful coroutines are basically threads (sometimes called microthreads or fibers to distinguish from C ABI/kernel thread construct) with a language-level construct for directly passing control to another thread.
Stackful coroutines are clearly a viable tool, but they don't work in all use cases. They require either segmented stacks, a precise GC, or memory usage comparable to kernel threads. They are tricky to implement correctly on Windows. Etc.
In my ideal world, we'd have stackless coroutines with great debugger support everywhere, with languages free to experiment with the syntax- explicit suspension points, implicit suspension points, effect polymorphism to make it look like you're yielding across nested function calls, etc...
I'd like to improve this situation, right now the following markers are commented out because I've had issues with them.
https://github.com/kurocha/concurrent/blob/8334ecf758b43eac3...
This is not a glib question, I genuinely don't know what the proper answer might be. Perhaps what's needed is a different debugger mechanism?
[1] https://github.com/spc476/C-Coroutines [2]
[2] More of a "proof-of-concept" than something really meant for production.
Hmm, what does this mean? I've used coroutines in Unity and to that respect, yielding functions in C# as well as generators in Python. The stacks are sane in the sense that they include the current running iteration.
Is that tricky to implement? Are you expecting something different? Seems pretty straight forward to me.
Notes from the course are fantastic, coroutines start here: https://www.student.cs.uwaterloo.ca/~cs343/documents/notes.p...
I'm disappointed the course teaches μC++ rather than referencing C++11 threading support.
The primitives uC++ make it very easy to form the concurrency models that are present in other languages and these days the prof does exactly that and shows exactly how to implement common models, such as channels, actors, and a few others.
Everything done is very mappable to how other languages provide concurrency.
As others have mentioned, uC++ is necessary because other runtimes lack the complete set of concurrency constructs that the course explores. It's essentially the path of least resistance to introducing CS students to all the different flavors of concurrency.
[1] https://www.student.cs.uwaterloo.ca/~cs343/documents/notes.p...
I would love to have applied test driven development to my courses.
I want to be sure I understand what is going on here to be sure.
Can someone offer an example of where this ability would be particularly useful?
I'm a particular fan of how coroutines work in Lua. Here's an article that helps explain them a bit in that context: http://leafo.net/posts/itchio-and-coroutines.html
We used to use them(Lua) in games to do scripted sequences and AI. Was simple enough that even our designers could edit/extend them.
It's a different model of control structure, primarily when you have a thing that produces data and a thing that consumes it. It could be in multiple threads, multiple machines, or just a single thread, so is often included in multiprocessing portions of designs, standards and instruction.
I recommend watching this video, which has a great overview. https://www.youtube.com/watch?v=_fu0gx-xseY
So you create another thread, have the main thread yield time to it, and at fixed points in this other thread yield back to the main thread. When the main thread yields to this other thread, all it's context is maintained and you don't need to "walk up" the stack to restore the work this thread was doing.
At a high level, this solves the class of problems where you need to do background tasks in applications that aren't thread safe. There are probably other places where these work well, but this is just my experience.
A key question right now is, can we have an implementation where the heap allocations that occur here don't have to? It's not 100% clear.
I think Rust clearly has an advantage here: since lifetimes are well-defined concept in the language itself, it should also be well-defined whether a generator can be allocated on the stack. Of course, I'm probably missing some hairy edge cases here.
Another aspect I found interesting was the ability to define custom code which runs every time a certain coroutine is suspended, or returns. In my reading, this allows for the coroutine to e.g. manage its own membership in a resume queue.
Tokio tackles this problem differently, but is this more powerful than Rust coroutines? Is there a mechanism by which a generic type could be used to wrap a generator and provide this functionality in a similar way? Asking partly as a point of conversation, and partly as someone who isn't fully steeped in Rust's type system yet.
On the other hand, "stackful coroutines" and "coroutines" without a qualifier often refers things with dynamically growing stacks.
It seems to me that the C++ Coroutines refer to the former, which likely complicates the terminology further.
In a nutshell they are still researching this but their general approach is to split the coroutine up and devirtualise/inline the parts where they can.
[0] https://llvm.org/devmtg/2016-11/Slides/Nishanov-LLVMCoroutin...
I had built a coroutine system for a Pascal environment by implementing NEWCOROUTINE and TRANSFER. Both turned out to be pretty simple in assembly language. The workspace contained an area for the CPU registers and the stack. So TRANSFER involved saving the registers of one coroutine in the workspace and restoring the registers from the second.