- Basic concept of task
When people deal with a large and complex problem in real life, The usual method is “divide and rule” “, that is, a big problem is decomposed into several relatively simple and easy to solve small problems, and the small problems are solved one by one, and then the big problems are solved. Similarly, when designing a more complex application, a large task is usually decomposed into multiple small tasks, and then these small tasks are run in the computer to finally achieve the purpose of completing the big task. This method can make the system run many times concurrently Tasks, so as to improve the utilization of processors and speed up the execution of programs. Therefore, modern operating systems are almost all multi task operating systems.
stay μ In c/os-ii, the program entity corresponding to the above small task is called “task”, and μ C/os-ii is a multi task operating system that can manage and schedule the operation of these small tasks.
- Task status
μ C/os-ii is designed according to the fact that there is only one CPU in the system. In this system, only one task will occupy the CPU at a specific time and be in the running state, while other tasks can only be in other states. According to the specific situation, μ There are five states of tasks in c/os-ii system.
Under the management of the system, a task can change between five different states. The conversion relationship is shown in Figure 1.1.

(1) Sleep state: when a task just resides in the program space in the form of code and has not been handed over to the operating system for management, it is called sleep state. Simply put, the state of a task when it is not equipped with a task control block or deprived of a task control block is called the sleep state of the task.
(2) Ready state: if the system is equipped with a task control block for the task and the ready table is registered in the task ready table, the state of the task is called ready state.
(3) Running state: if the task in the ready state has obtained the CPU usage right through the judgment of the scheduler, the task will enter the running state. Only one task can be in the running state at any time. The ready task can enter the running state only when all tasks with higher priority than this task are turned to the waiting state.
(4) Waiting state: when a running task needs to wait for a period of time or wait for an event to occur before running, the task will give the CPU usage right to other tasks and make the task enter the waiting state.
(5) Interrupt service status: once a running task responds to the interrupt application, it will stop running and execute the interrupt service program. At this time, the status of the task is called interrupt service status.
- Task readiness table and task scheduling
It is the core work of a multitasking operating system to allocate CPUs to the ready tasks in the system. This work involves two technologies: one is to judge which tasks are ready; Second, task scheduling. The so-called task scheduling is to determine the tasks that should run immediately in the ready tasks through an algorithm. The program module used by the operating system to be responsible for this work is called scheduler.
1) Task readiness table structure
Each task is assigned a different priority level, from level 0 to the lowest priority OS_ LOWEST_ Prio, each ready task is placed in the task readiness table, which has two variables, osrdygrp and osrdytb1[], as shown in Figure 1.2.

In osrdygrp, tasks are grouped by priority. Eight tasks are a group. Each bit in osrdygrp indicates whether each group of eight tasks has a task in the ready state. When the task enters the ready state, the corresponding position of the corresponding element in the osrdytb1[] port of the ready table is also set to 1. The relationship rules between osrdygrp and osrdytb1[] are as follows:
When any bit in osrdytb1[0] is 1, the 0th position of osrdygrp is 1;
When any bit in osrdytb1[1] is 1, the first position of osrdygrp is 1:
When any bit in osrdytb1[2] is 1, the second position of osrdygrp is 1:
When any bit in osrdytb1[3] is 1, the third position of osrdygrp is 1;
When any bit in osrdytb1[4] is 1, the fourth position of osrdygrp is 1;
When any bit in osrdytb1[5] is 1, the 5th position of osrdygrp is 1;
When any bit in osrdytb1[6] is 1, the 6th position of osrdygrp is 1:
When any bit in osrdytb1[7] is 1, the 7th position of osrdygrp is 1
Since the variable osrdygrp has 8 binary bits, each of which corresponds to an element of the osrdytb1[] array, and each element can record the ready status of 8 tasks, therefore, μ C/os-ii can manage up to 8×8=64 tasks.
How to find the position of the task in the ready table according to the priority of the task? Since the priority level is a single byte number, and its maximum value will not exceed 63, that is, 0011111 in binary form, the priority level can be regarded as a 6-bit binary number, so the high 3 bits (d5d4d3)) can be used to indicate the specific data bits of the variable osrdygrp, and determine the subscript of the array element of the readiness table; Use the lower 3 bits (d2d1d0) to indicate the specific data bits of the array element, as shown in figure 1.3

2) Task scheduling
μ The task scheduling idea of c/os-ii: “approximately keep the ready task with the highest priority running all the time.” In practice, it calls the scheduler when the system or user task calls the system function and executes the interrupt service program to determine the task that should run and run it.
The main work of the scheduler: in a multitasking system, the work of making the CPU stop the currently running task and run another task is called task switching, and the work of task switching according to a certain rule is called task scheduling.
stay μ In c/os-ii, task scheduling is completed by task scheduler. There are two main tasks of task scheduler: one is to find the ready task with the highest priority in the task ready table; The second is to achieve task switching. μ C/os-ii has two kinds of schedulers: one is task level scheduler; The other is interrupt level scheduler. The task level scheduler is implemented by the function ossched (), while the interrupt level scheduler is implemented by the function osintext (). Here we mainly introduce the task level scheduler ossched ().
The scheduler divides the task switching into two steps: the first step is to obtain the thread control block of the task to be run
(thread control block, TCB) pointer: the second step is to switch the breakpoint data. Because the operating system manages tasks through the task control block TCB of tasks, the main work before the scheduler really implements task switching is to obtain the task control block pointer of the task to be run and the task control block pointer of the current task.
Because the pointer of the task control block of the aborted task is stored in the global variable ostcbcur, the work of the scheduler is mainly to obtain the pointer of the task control block of the task to be run.
μ C/os-ii allows applications to lock and unlock the scheduler by calling the functions osschedlock() and osschedunlock(). In order to record the locking and unlocking of the scheduler, μ C/os-ii defines a variable oslocknesting. Every time the scheduler is locked, the variable oslocknesting will be increased by 1; On the contrary, every time the scheduler is unlocked, the variable oslocknesting will be reduced by 1. Therefore, you can know the nesting times of the scheduler locking and unlocking by accessing the variable oslocknesting.
- Task creation
As we can see from the previous content, μ C/os-ii manages tasks through task control blocks. Therefore, creating a task is essentially creating a task control block, and associating the task code with the task stack through the task control block to form a complete task. Of course, it is also necessary to make the newly created task enter the ready state, and then trigger a military scheduling.
μ C/os-ii has two functions for creating tasks: ostaskcreate() and ostaskcreateext(). Ostaskcreateext() is an extension of ostaskcreate() and provides some additional functions. Users can use one of these two functions to create tasks as needed.
1) Create a task with the function ostaskcreate()
The application creates a task by calling the function ostaskcreate(). The source code of the function ostaskcreate() is as follows:
From the source code of the function ostaskcreate(), we can see that the function makes a series of judgments about the priority of the task to be created. After confirming that the priority is legal and not used, then call the functions ostaskstkinit) and ostcbinit) to initialize the task stack and task control block. After successful initialization, in addition to adding 1 to the task counter, further judgment is required μ Whether the kernel of c/os-ii is running, that is, whether the value of osrunning is 1. If the value of osrunning is 1, call ossched() to schedule tasks.
After calling the function ostask create() successfully, it will return OS no err: otherwise, it will return prio invalid, OS prio exist and the information returned when calling the task control block initialization function in the function fails according to the specific situation.
2) Create a task with the function ostaskcreateext() create a task with the function ostaskcreateext(), and some additional parameters will be added. The function source code is as follows:
Generally speaking, a task can be created before calling the function osstart() to start task scheduling, or it can be created in a task. however μ C/os-ii has a provision that at least one task must have been created before calling the start task function osstart (). Therefore, it is customary for people to create a task before calling the function osstart() and give it the highest priority, thus making it the starting task; Then create other tasks in this starting task
- Suspension and recovery of tasks
Suspending a task means stopping the operation of the task
stay μ In c/os-ii, user tasks can suspend themselves or other tasks except idle tasks by calling the system function ostasksuspend(). The task suspended with the function ostasksuspend() can only be restored to the ready state by calling the recovery function ostaskresume() in other tasks. The transition relationship between the running state, ready state and waiting state of the task is shown in figure 1.4.

1) Suspension of tasks
The prototype of the suspended task function ostasksuspend() is as follows:
INT8U OSTasksuspend(INT8U prio);
The parameter prio of the function is the priority of the task to be suspended. If the task calling the function ostasksuspend() wants to suspend itself, the parameter must be constant OS prio self (the constant is in the file μ C/os-ii, h is defined as oxff), when the function call is successful, the information OS no err is returned: otherwise, OS task suspend idle, OS prio invalid, OS task suspend prio, etc. are returned according to the specific circumstances of the error
As shown in Figure 1.5, this function mainly determines whether the task to be suspended calls the task itself of this function in a series of judgments. If it is the task itself, you must delete the ready flag of the task in the task ready table, and trigger a task scheduling after making a pending record in the task control block member ostcbstat, so that the CPU can run other tasks that are ready. If the task to be suspended is not the task calling the function itself, but other tasks, then just delete the readiness flag of the suspended task in the task readiness table and make a suspension record in the task control block member ostcbstat.
For more information click here