ProtoThreads: Lightweight, Stackless Threads in C
dunkels.com
dunkels.com
> Because protothreads do not save the stack context across a blocking call, local variables are not preserved when the protothread blocks. This means that local variables should be used with utmost care - if in doubt, do not use local variables inside a protothread!
It is hardly a coroutine at all if no state, other than the instruction pointer, is preserved.
[1] See the lua coroutine papers where the nomenclature is introduced.
You could have threads with enough memory for the base levels local variables. It would mean you wouldn't need global variables to keep state, but it would still be stackless as you can't pause execution within a function call.
what does that even mean? Sure you could calculate what stacksize your exact programm would need at maximum, if you unroll everything, but you could not define a fixed "base level" of a stacksize for every single programm out there, could you?
The topmost stack frame. That's what "stackless" generally implies: it doesn't preserve the stack itself, that doesn't mean it preserves nothing.
That's what you see with most async/await systems (as opposed to more integrated "lightweight thread" systems like Erlang or Go), yield points blow the stack (though it may be relinked for debugging purposes), but they don't break local variables.
That said, I’d hope that someone using a C library like this wouldn’t just start using it without understanding the potentially non-trivial consequences/side-effects of that decision.
https://news.ycombinator.com/item?id=19907229
And 5 years ago:
So if it's still single-threaded, then this is basically a cumbersome async/await right?
Duff’s device along with the __LINE__ trick enables the creation of automatic DFAs useful to generate coroutines, protothreads and async/await alike.
Also, this is less like a goto, and more like a setjmp/longjmp.
You want something to create a union of all the relevant local variables of each state. Doing this efficiently is non compositional and so requires language support.
Many control operators involve continuations with closures, and cannot be desugared to goto as such.
(Don't get me wrong, this may be technically interesting, but... choose your tools with care.)
What other languages would you suggest that supports the use-case that this is aimed at?
> Protothreads are extremely lightweight stackless threads designed for severely memory constrained systems, such as small embedded systems or wireless sensor network nodes.
https://apple.github.io/swift-corelibs-libdispatch/tutorial/
> Protothreads are extremely lightweight stackless threads designed for severely memory constrained systems, such as small embedded systems or wireless sensor network nodes. Protothreads provide linear code execution for event-driven systems implemented in C. Protothreads can be used with or without an underlying operating system to provide blocking event-handlers. Protothreads provide sequential flow of control without complex state machines or full multi-threading.
libdispatch has none of the features listed above. You're right that libdispatch is a better choice for typical PC software -- but this is designed for devices like an 8-bit microcontroller with a kilobyte of RAM.
Linear code execution can be done using a serial queue.
Even on PCs with tons of resources, thread pools and coroutines are not always interchangeable.
One reason is performance, accessing a cache line shared across cores is even more expensive than cache miss.
Besides performance, writing same data from multiple threads, or doing in parallel what must be running sequentially, is a common source of bugs.
Maybe the queuing part. However the "work" (block, callback, etc) is typically dynamically allocated thingy, which can be quite expensive (and is a no-go for lots of embedded systems).
But fair play for turning it into a working library.
Duff's device to ProtoThreads is what a paintbrush is to a painting.
One is a construct for conditional loop unrolling, but it takes a stroke of genius to apply it in an absolutely orthogonal way to implement a functional cooperative multithreading with just a handful of macros. Duff's device was nowhere close to be meant for that, so your condescending pat on a back for "turning it into a working library" is completely inappropriate.
So even they admit it isn't entirely their own work, and I still see no reason to claim they "invented" it.
edit: my "pat on the back" was absolutely not "condescending". Turning a neat design in theory into a safe, functional implementation is not to be sniffed at.
There's an alternate one that uses the "labels as values" feature supported by GCC and Clang, which is much more elegant. In particular, it allows you to have a 'switch' statement inside the protothread.
https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
from 2000.