In embedded system, process and thread are often called task. The only reason for multitasking is because most tasks spend most of their execution time on waiting for an event or timeout happen. If we can run other pieces of codes when waiting for an event, performance must increase a lots. The benefit of multitasking is (1) avoid long response time due to waiting for event, (2) better utilize resource, keep them all busy. The following shows typical task code:
void task (void *data)
{
init_task();
while (TRUE)
{
Wait for message at task mailbox();
// go to pending(blocked) queue if message is not ready
switch (message.type)
{
case MESSAGE_TYPE_X:
// ...
break;
case MESSAGE_TYPE_Y:
// ...
break;
}
}
}
It is similar to code of polled waiting, but they are different things. After initialization, it runs a infinite loop which is to wait for a specific event or message, and then processes the message. In a typical embedded system, tasks are viewed as backgroundprocedures, and the ISR that provides the message are viewed as foreground procedures.
How does it work
Semaphore
When the task tries to obtain message data, it calls Wait() on a semaphore. If message has not been ready, the task is blocked. When the corresponding ISR generates the message, the ISR calls Signal() on this semaphore, and wake up the task. The task can then process the data.
System call
When the task tries to obtain message data, it call the system call Block() if the data has not been ready, so CPU will execute other tasks. When the corresponding ISR generates the message, the ISR first calls a system call to change the status of this task from pending to ready, and then calls a system call to execute the CPU scheduler. After that, the scheduler might (or might not, may depend on the priority) wake up the task to process the data.
沒有留言:
張貼留言