Hacker News new | past | comments | ask | show | jobs | submit login

These seem to work with some clever (ab)use of switch statements: http://dunkels.com/adam/pt/expansion.html



That was the original implementation (and still used for non-GNU C).

On GCC and Clang though, labels-as-values allows a cleaner implementation: https://github.com/Akagi201/protothreads/blob/master/include...


Woo. I wrote the original implementation for that 14 years ago. I discovered local labels when we tried to write some code that used the had multiple yields in the same line. Due to how the switch based implementation worked, this wasn't possible, so I looked for other solutions.


Wait, how does this work with local variables? Wouldn't the scope be destroyed when you returned, how can it restore the stack if it doesn't save information in the local continuation?


Indeed, there is a problem with local variables. The example relies on using global variables. If you want multiple threads executing the same function, it is not going to work. Also there is no solution for calling other functions (and have them switch in the middle). A long time ago, I worked on an implementation that does not have these limitations. See: http://www.iwriteiam.nl/Ha_cmt.html


> The example relies on using global variables.

It could as well rely on local variables with static lifetime, though.

> If you want multiple threads executing the same function, it is not going to work.

That's true for the example, but in general the solution is to pass the protothreads the thread-local state in a struct.


> > The example relies on using global variables.

> It could as well rely on local variables with static lifetime, though.

For those following along, static local variables are the same thing as static global variables[1], C just enforces a scoping restriction as to who can access it at compile time. Most compilers will emit the same BSS section entries for both (though they will mangle the symbol name). It's basically compiler syntactic sugar for most compilers (though I'm sure the actual standard itself allows for some weird exotic use cases where they get handled completely differently).

[1] Static global variables are symbols that are restricted to a compilation unit (as opposed to regular global variables that can be linked to from another compilation unit). If you run `nm` on them, they'll all have a lower case letter indicating it's type.



If I understand it correctly, it doesn't. That's why they're called stackless threads. Variables local to the stack frame lose their state, so any internal state needs to be stored in a global.


The article mentions Duff's Device. And yes it works.


IIRC when Simon Tatham first proposed the mechanism, he suggested it should never be used in production, and whoever does so should be fired!


Quite the opposite, actually. He said that he will probably be fired, but should still insist on it being the right way: "Any coding standard which insists on syntactic clarity at the expense of algorithmic clarity should be rewritten. If your employer fires you for using this trick, tell them that repeatedly as the security staff drag you out of the building." https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html


Excitingly, we soon may be able to have both (if you can compile your C code with a C++ compiler). Coroutines are in the working draft for the C++20 spec, so they may soon be provided by the runtime (and thus integrate into all of the other language features and syntax) instead of requiring hacking it up with string macros: https://en.cppreference.com/w/cpp/language/coroutines


If you want coroutines before upgrading to a C++20 toolchain, you can also try:

- boost::Fiber for C++: https://www.boost.org/doc/libs/1_70_0/libs/fiber/doc/html/in...

- boost::coroutine2 for C++: https://www.boost.org/doc/libs/1_70_0/libs/coroutine2/doc/ht... (lower level than boost::Fiber, and doesn't include an internal scheduler)

- libtask for C: https://swtch.com/libtask/

In the C++ context, this doc summarizes the distinction between "fibers" and "coroutines", although the terminology is not consistent across language ecosystems: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n402...


D also has fibers, and good C/C++ integration, so that could be an option too.

http://ddili.org/ders/d.en/fibers.html


Adam is a CEO of Thingsquared =D




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: