Hi guys,
I read for the first time this topic now and to be honest I do not understand completly the continuation system. So perhaps I should not write this, but still this topic is about thread related abstractions, so I will give you mine idea.
In many of my embedded projects I have used a concept that is alternative to the threads. Instead of threads I use "modules".
When the modules are running they have their own CPU context and basically they look like threads.
Now, let me explain the differences:
1)
The threads, usually are loops. You create the thread then you wait for an event to process, then another one and so on...
In order to be able to catch an event, you need to create first the thread, which means that the thread is eating memory even if it is just waiting.
The modules are more like functions. First you declare the function so the OS and the rest of the world knows about it. But this does not start the function automatically. Someone has to send a "request".
With other words, the module is actualy a black box that can accept "requests" and after processing it may return "responses".
The OS is responsible to queue all incomming requests and to call the module function (as a task). When the function returns, the OS will restart it with the next request if any or kill the context.
2)
The threads have priorities. Most of the OSes are based on RMA scheduler. So the user knows that if there are two threads ready and which one will get the CPU. In most of the cases, the system is quite predictable.
What the people fail to undesrtand usualy here is that in order to make the system more efficient, the threads should be assigned with priority according to their rate, not the importance!
From other side, we can assign importance to the modules. For example imagine a mobile device with two modules - UART and battery charger.
We can say, that the charger is more important, because failures in the charger can blow the device off. While failures in the UART can loose some bytes only. We can also give some time to the requests. For example, if we want to send something on the UART we would like this to be done in miliseconds, while for the charger is enough to check it once in few seconds. This time, is actualy a "laxity" for the task.
One possible approach to determine which module will gain the CPU is to combine the laxity and the importance in a single number. Where the laxite will decrement down to zero. So if the OS has two modules ready to execute, it will preffer the module with lower laxity. So usually the UART will have priority over the charger. Unless they both become critical - with zero laxity. Then the one with more importance wins.
3) multitasking communications.
With threads it is usually a hell to make communications between various tasks. The OS provide some tools, but the main effort remains - it is easier to go over TCP/IP rather to talk between tasks.
The modules, can have addresses so in order to make a request to another module you need the address. And that's all. You don't care if the other module is running, busy etc. You just prepare a request, containg the sourse, destination and the time allowed. Then you choose to block the current execution until the response is ready, or you may continue (checking the response later or specifying that you don't care about the response). The OS is responsible to route the request, even if is not to the same CPU, host, or network.
Note that the requests have a time frame, so if a task sends a blocking request to a remote module, the local kernel will resume the task, if there is a timeout or no response.
PS
In many cases, such a modular system is more efficient than traditional thread based OS. Especially for embedded systems - you get better scheduling, better use of the resurses and simpler software design. Once you start writting modules, you define clear interfaces between them - you just have to do it.
While with threads - who defines what a thread does? Two threads written from different guys usually means problems, because one of them usually will think he is very important and won't sleep.
While the modules do not loop - they have a piece of work to do and when they are done - they exit. Eventually releasing memory etc.
Since this is a concept, many OS related functionality can use it as well. For example - the dynamic memory. When you try to allocate memory you send a request... If there is no free memory at the moment - you wait... If you are lucky, you will get the requested memory before your deadline. No extra code is required and everything is simple and safe.
It is also very easy to debug and interface such a system. Since the OS serves as a router, you can change the routing tables and "replace" some modules (like display or keyboard) from the target to the host or whatever.
Please excuse me if you think this is not related to the topic