3 ms·
I'm currently writing a GUI for industrial automation, where we have to talk to a number of machine control threads and image processing threads (all through a
by jstimpfle 9y ago
I'm currently writing a GUI for industrial automation, where we have to talk to a number of machine control threads and image processing threads (all through a procedural interface that connects to other processes).
I'm writing in C and decided to stay in a single OS thread and to instead write my own simplistic user thread scheduler. User thread ("green threads") work by simply switching call stacks and saving registers. In my case this is as simple as making a few Windows API calls like CreateFiber() or SwitchToFiber().
It's one of the best things I've ever done. Maybe 1 day of work to get the threads rolling, no bugs, and still in a familiar C environment. No bindings required to interface with the libraries that I need to interface with (like Qt) and perfect deterministic control over what happens (just not the other processes of course).
I think I can understand people are not using C doing web stuff (lots of strings) but for what I do I'm convinced it's the easiest, fastest to develop, most performant, most robust thing you can do.
- lucidguppy 9y agoHow can you be convinced if you're only running the control in an experiment?
- jstimpfle 9y agoIt's not an experiment.
- todd8 9y agoI don't believe that lucidguppy was saying that your system was an experiment. Instead, it would be interesting to try implementing your system in a second language so you could compare and contrast the differences. (Of course, in the real-world one often doesn't have the luxury of doing this.)
- jstimpfle 9y agoOk, so my conviction comes from the fact that the code is super straight-forward and I don't have to deal with the complexities of a managed language's run-time system (like tuning the garbage collector or scheduler, using synchronisation primitives, depending on the ecosystem/using terrible bindings, etc). All investment is just a page of code using the Windows Fiber API, and the scheduler ist just 10 lines of code doing round-robin scheduling. Which is totally fine right now, and there's the added benefit of being in total control and being able to make adjustments if they are needed in the future. Since the scheduling is non-preemptive, threads are not allowed to block. But only a synchronous, blocking coding style is maintainable, so threads use wrapper functions to execute slow operations. The wrapper functions have a synchronous interface, but internally they call asynchronous functions, and unless the request can be served immediately, they call the scheduler. The wrapper functions make another 50 lines (so far) of really simple bullet-proof maintainable code. It's really like Javascript technically (non-preemptive scheduling), but you don't have to do callback chaining. You just write your code in an ordinary synchronous blocking style. Think about that. You write thread-heavy interactive C code that is much more maintainable than Javascript code. And of course, much more maintainable than clumsy OS threads - no management, no synchronisation primitives and no excessive copying between threads. On top of that, the scheduling is deterministic. All with 100 lines of straightforward infrastructure code. The only boilerplate in the project comes from using Qt/Qml. (If you're on POSIX and can't use the Windows Fiber API, you can depend on the deprecated makecontext/getcontext/setcontext API, or write a little inline assembly. It's not a big deal either way, since it's really just a few lines of code that are neatly separated from the rest of the system).
- ac2u 9y agoWould be nice to see a blog post expanding on this a little more with more examples and some basic diagrams.