Adam Dunkels, an embedded systems researcher and creator of Contiki OS, writes about protothreads and tiny TCP/IP stacks in C.
Commenters treat Protothreads as an embedded classic and call it simple and beautiful, linking its expansion page to explain the switch/case trick.
I got to about 500K processes on Erlang's VM on an i7 with lots of memory.
These people people got up to 2M concurrent TCP connections
http://blog.whatsapp.com/index.php/2012/01/1-million-is-so-2011/
And on top of it, it is using isolated heaps. That is beautiful I think. Completely concurrent GC is beautiful.
I know Erlang syntax is not to for everyone's taste (I do like it though). There is also Elixir (http://elixir-lang.org/). But the underlying BEAM VM is an awesome piece of technology.
> The thought was to have a billion threads on a SPARCStation 10
There are some green-thread C libraries I've been playing with, like Protothreads ( http://dunkels.com/adam/pt/index.html ) and libconcurrency ( https://code.google.com/p/libconcurrency/ ) I think they use setjump/longjump trick. Some use setcontext()/getcontext() POSIX call.
I still like Erlang VM best.
Personally I no longer use pure state machines, as they can become beasts and end up being a royal pain to maintain.
Instead, I use 'duff devices' variations of it (in C) which breaks down the machine into code that looks 'linear' enough, but is in fact, a state machine without the drawbacks.
I've implemented quite a few protocol stacks using that 'trick' and it's still very nice to read/maintain -- the good thing is that it roughtly looks like a coroutine/thread, without any runtime requirements, so will work just fine on embedded systems as well. Same as coroutine/state machines, don't make your 'states' too 'long' or CPU intensive, you'll have the same consequences.
There's an implementation floating around called 'protothreads' [0], but you can really do pretty much the same with a handful of macros.
[0]: http://dunkels.com/adam/pt/
From a net-effect standpoint, Rust's implementation of async/await is fairly similar to protothreads, which were used even on smaller AVR and MSP430 targets where rtos threads weren't practical.
That being said, protothreads were implemented using wildly cursed C macros, and offered none of the safety guardrails that Rust has, nor the ergonomics, and had some insane constraints, like "you can't use local variables at all, only statics" because like rust, they were stackless coroutines that meant you would have no control of the stack across await points.
If you were VERY CAREFUL, you could get the same lightweight concurrency with almost the same fundamental model. Woe be on you if you ever had to debug though.
edit - here's a look at how protothreads were expanded: https://dunkels.com/adam/pt/expansion.html
?? Duff's Device[0] theme song??
10b integers get pushed into an array. Does one need an unfold operation to C the union of (&*p) bits get "twidded n by n, ..." and 'ants go marching n x n' [1].
Couldn't find an appropriate utf-32 glyph for the base case.
Does the 'BOOM' happen at 0, NULL or NILL?
------
Limited HN ability to Hollerith when there's to much Babbage[2], (aka insufficient HN article space), for Simon/Garfunkel electric glow wall for the perl camel example.
------
[0]: duff's device : https://en.wikipedia.org/wiki/Duff%27s_device proto threads : https://dunkels.com/adam/pt/ coroutines : http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
[1] : file:///home/surf/Downloads/counting-and-math-rhymes-002-the-ants-go-marching.pdf
[2] : https://engines.egr.uh.edu/episode/1145
Don't miss out on the brilliant link at the bottom - Adam Dunkels' Protothreads - Lightweight, Stackless Threads in C also uses nested switch/case statements [1].
I learned about the theory with it, and used his library to implement cooperative multitasking on a bare metal embedded AVR C project. I wrote a task manager and dispatcher based on Protothreads, and that effort was what later made it simple for me to understand the JS async/await paradigm that would appear under my radar a couple years later.
EDIT to add that I think the concepts might still apply, since these days I've seen things like stackless async coroutines discussed for Rust... didn't study those in detail yet, but I wouldn't be surprised if the basic concepts are the same.
[1]: Current website: http://dunkels.com/adam/pt/
This is a fascinating concept that I've written about before: "C#’s async/await compared to protothreads in C++". [1] Both async/await in C# and protothreads [2] in C unroll control flow to a state machine. In C, this is done using some simple but crazy macros using the fact that you can interleave switch statements with other control flow (ala Duff's Device [3]).
Many years ago I ported Adam Dunkel's protothreads library to C++ [4]. You can use C protothreads in C++ directly, of course, but it's a bit nicer to use classes.
[1] https://blog.brush.co.nz/2012/11/async-await-protothreads-cpp/
[2] http://dunkels.com/adam/pt/
[3] https://en.wikipedia.org/wiki/Duff%27s_device
[4] https://github.com/benhoyt/protothreads-cpp/