Embedded operating systems sound quite impressive, but in fact, they are just a streamlined version of an operating system, specially tailored for embedded devices. Today, let’s talk about a particularly interesting embedded operating system – the one based on priority cooperative scheduling. It’s a bit like a well-organized small team, where each member has their own tasks and priorities, working together to get things done.
What is Cooperative Scheduling?
Imagine you and your friends are cleaning a room. You discuss and agree that each person is responsible for one area, and once you finish your part, you actively let others take over. This is the basic idea of cooperative scheduling. In our embedded system, each task is like a little buddy, executing back and forth according to agreed rules.
void task1() {
while(1) {
// Do something
yield(); // Actively yield CPU
}
}
void task2() {
while(1) {
// Do something else
yield(); // Also actively yield CPU
}
}
As you can see, after each task completes its work, it calls the yield()
function to actively hand over control. This is the essence of cooperation.
What About Priority?
Since it’s cooperation, there must be some rules. Priority is that rule. Imagine you have a to-do list at home, where some tasks are more urgent than others. In our system, each task also has a priority; the smaller the number, the higher the priority.
typedef struct {
void (*task_func)();
int priority;
} Task;
Task task_list[] = {
{task1, 1},
{task2, 2},
// More tasks can be added
};
This piece of code defines a task structure that includes the task function and priority. Then we put all tasks into an array for easier management.
Scheduler: The Commander is Online
The scheduler is the brain of the entire system, deciding which task to execute next. Our scheduler will first execute the task with the highest priority, and if this task actively yields the CPU, it will look for the next highest priority task.
void scheduler() {
while(1) {
for(int i = 0; i < sizeof(task_list)/sizeof(Task); i++) {
if(is_ready(task_list[i])) {
task_list[i].task_func();
}
}
}
}
This scheduler seems simple but is quite interesting. It continuously traverses the task list and executes any ready tasks (determined by the is_ready()
function).
Friendly reminder: In actual systems, the is_ready()
function may check more complex conditions, such as whether a task is blocked or if resources are available.
Real-World Application Scenarios
Imagine you are building a smart home control system. You might have several main tasks:
- Reading the temperature sensor (high priority)
- Controlling the air conditioning (medium priority)
- Updating the display (low priority)
void read_temperature() {
while(1) {
// Read temperature
yield();
}
}
void control_ac() {
while(1) {
// Control AC based on temperature
yield();
}
}
void update_display() {
while(1) {
// Update display
yield();
}
}
Task task_list[] = {
{read_temperature, 1},
{control_ac, 2},
{update_display, 3}
};
This way, the system will prioritize reading the temperature, then controlling the air conditioning, and finally updating the display. However, because it is cooperative, even the lowest-priority display task will get a chance to execute, preventing starvation.
Pits and Precautions
Although this system looks quite good, there are also pitfalls:
-
If a task forgets to call
yield()
, the entire system will hang. It’s like a classmate monopolizing the broom and not letting go, preventing others from working. -
Real-time performance is not very good. If there is a high-priority task that takes a long time, low-priority tasks may have to wait a long time to execute.
-
Debugging can be quite troublesome. Because task switching is cooperative rather than preemptive, it can sometimes be difficult to identify where the problem lies.
In the end, while this priority-based cooperative scheduling embedded operating system is simple, it is still quite practical for some small embedded devices. It does not require complex hardware support, has a small codebase, and is easy to understand and implement. Of course, if your system requires high real-time performance or isolation between tasks, you may need to consider other more complex solutions. However, for beginners learning about embedded operating systems, this is definitely a good start!