1# 任务 2 3 4## 基本概念 5 6从系统的角度看,任务Task是竞争系统资源的最小运行单元。任务可以使用或等待CPU、使用内存空间等系统资源,并独立于其它任务运行。 7 8OpenHarmony 内核中使用一个任务表示一个线程。 9 10OpenHarmony 内核中同优先级进程内的任务统一调度、运行。 11 12OpenHarmony 内核中的任务采用抢占式调度机制,同时支持时间片轮转调度和FIFO调度方式。 13 14OpenHarmony 内核的任务一共有32个优先级(0-31),最高优先级为0,最低优先级为31。 15 16当前进程内, 高优先级的任务可抢占低优先级任务,低优先级任务必须在高优先级任务阻塞或结束后才能得到调度。 17 18**任务状态说明**: 19 20- 初始化(Init):任务正在被创建。 21 22- 就绪(Ready):任务在就绪列表中,等待CPU调度。 23 24- 运行(Running):任务正在运行。 25 26- 阻塞(Blocked):任务被阻塞挂起。Blocked状态包括:pending(因为锁、事件、信号量等阻塞)、suspended(主动pend)、delay(延时阻塞)、pendtime(因为锁、事件、信号量时间等超时等待)。 27 28- 退出(Exit):任务运行结束,等待父任务回收其控制块资源。 29 30 **图1** 任务状态迁移示意图 31 32 ![zh-cn_image_0000001173399977](figures/zh-cn_image_0000001173399977.png) 33 34**任务状态迁移说明:** 35 36- Init→Ready: 37 任务创建拿到控制块后为初始化阶段(Init状态),当任务初始化完成将任务插入调度队列,此时任务进入就绪状态。 38 39- Ready→Running: 40 任务创建后进入就绪态,发生任务切换时,就绪列表中最高优先级的任务被执行,从而进入运行态,此刻该任务从就绪列表中删除。 41 42- Running→Blocked: 43 正在运行的任务发生阻塞(挂起、延时、读信号量等)时,任务状态由运行态变成阻塞态,然后发生任务切换,运行就绪列表中剩余最高优先级任务。 44 45- Blocked→Ready : 46 阻塞的任务被恢复后(任务恢复、延时时间超时、读信号量超时或读到信号量等),此时被恢复的任务会被加入就绪列表,从而由阻塞态变成就绪态。 47 48- Ready→Blocked: 49 任务也有可能在就绪态时被阻塞(挂起),此时任务状态会由就绪态转变为阻塞态,该任务从就绪列表中删除,不会参与任务调度,直到该任务被恢复。 50 51- Running→Ready: 52 有更高优先级任务创建或者恢复后,会发生任务调度,此刻就绪列表中最高优先级任务变为运行态,那么原先运行的任务由运行态变为就绪态,并加入就绪列表中。 53 54- Running→Exit: 55 运行中的任务运行结束,任务状态由运行态变为退出态。若为设置了分离属性( 由头文件 los_task.h 中的宏定义 LOS_TASK_STATUS_DETACHED 设置)的任务,运行结束后将直接销毁。 56 57 58## 运行机制 59 60OpenHarmony 任务管理模块提供任务创建、任务延时、任务挂起和任务恢复、锁任务调度和解锁任务调度、根据ID查询任务控制块信息功能。 61 62用户创建任务时,系统会将任务栈进行初始化,预置上下文。此外,系统还会将“任务入口函数”地址放在相应位置。这样在任务第一次启动进入运行态时,将会执行任务入口函数。 63 64 65## 开发指导 66 67 68### 接口说明 69 70##### 表1 任务的创建和删除 71 72| 接口名 | 接口描述 | 73| ------------------ | ------------------------------------------------------------ | 74| LOS_TaskCreate | 创建任务,若所创建任务的优先级比当前的运行的任务优先级高且任务调度没有锁定,<br/>则该任务将被调度进入运行态 | 75| LOS_TaskCreateOnly | 创建任务并阻塞,任务恢复前不会将其加入就绪队列中 | 76| LOS_TaskDelete | 删除指定的任务,回收其任务控制块和任务栈所消耗的资源 | 77 78##### 表2 任务的状态控制 79 80| 接口名 | 接口描述 | 81| --------------- | ------------------------------------------------------------ | 82| LOS_TaskResume | 恢复挂起的任务 | 83| LOS_TaskSuspend | 挂起指定的任务,该任务将从就绪任务队列中移除 | 84| LOS_TaskJoin | 阻塞当前任务,等待指定任务运行结束并回收其资源 | 85| LOS_TaskDetach | 修改任务的 joinable 属性为 detach 属性,detach 属性的任务运行结束会自动回收任务控制块资源 | 86| LOS_TaskDelay | 延迟当前任务的执行,在延后指定的时间(tick数)后可以被调度 | 87| LOS_TaskYield | 将当前任务从具有相同优先级的任务队列,移动到就绪任务队列的末尾 | 88 89##### 表3 任务调度 90 91| 接口名 | 接口描述 | 92| -------------------- | ------------------------------------------------------------ | 93| LOS_TaskLock | 锁定任务调度,阻止任务切换 | 94| LOS_TaskUnlock | 解锁任务调度。通过该接口可以使任务锁数量减1,若任务多次加锁,那么<br/>任务调度在锁数量减为0时才会完全解锁 | 95| LOS_GetTaskScheduler | 获取指定任务的调度策略 | 96| LOS_SetTaskScheduler | 设置指定任务的调度参数,包括优先级和调度策略 | 97| LOS_Schedule | 触发主动的任务调度 | 98 99##### 表4 任务相关信息获取 100 101| 接口名 | 接口描述 | 102| ------------------------ | ------------------------ | 103| LOS_CurTaskIDGet | 获取当前任务的ID | 104| LOS_TaskInfoGet | 获取指定任务的信息 | 105| LOS_GetSystemTaskMaximum | 获取系统支持的最大任务数 | 106 107##### 表5 任务优先级 108 109| 接口名 | 接口描述 | 110| ----------------- | ------------------------------ | 111| LOS_CurTaskPriSet | 设置当前正在运行的任务的优先级 | 112| LOS_TaskPriSet | 设置指定任务的优先级 | 113| LOS_TaskPriGet | 获取指定任务的优先级 | 114 115##### 表6 任务绑核操作 116 117| 接口名 | 接口描述 | 118| ------------------ | ------------------------------------------- | 119| LOS_TaskCpuAffiSet | 绑定指定任务到指定CPU上运行,仅在多核下使用 | 120| LOS_TaskCpuAffiGet | 获取指定任务的绑核信息,仅在多核下使用 | 121 122 123 124### 开发流程 125 126任务的典型开发流程: 127 1281. 通过LOS_TaskCreate创建一个任务。 129 - 指定任务的执行入口函数 130 - 指定任务名 131 - 指定任务的栈大小 132 - 指定任务的优先级 133 - 指定任务的属性,LOS_TASK_ATTR_JOINABLE和LOS_TASK_STATUS_DETACHED属性 134 - 多核运行时,可以选择设置任务的绑核属性 135 1362. 任务参与调度运行,执行用户指定的业务代码。 137 1383. 任务执行结束,如果设置了 LOS_TASK_STATUS_DETACHED 属性,则自动回收任务资源,如果任务设置了 LOS_TASK_ATTR_JOINABLE 属性,则需要调用LOS_TaskJoin 回收任务资源,默认为 LOS_TASK_STATUS_DETACHED 属性。 139 140> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** 141> - 内核态具有最高权限,可以操作任意进程内的任务。 142> 143> - 用户态进程通过系统调用进入内核态后创建的任务属于KProcess, 不属于当前用户态进程。 144 145 146### 编程实例 147 148代码实现如下(该示例代码的测试函数可以加在 kernel /liteos_a/testsuites /kernel /src /osTest.c 中的 TestTaskEntry 中进行测试。): 149 150 151```c 152UINT32 g_taskLoID; 153UINT32 g_taskHiID; 154#define TSK_PRIOR_HI 4 155#define TSK_PRIOR_LO 5 156UINT32 ExampleTaskHi(VOID) 157{ 158 UINT32 ret; 159 PRINTK("Enter TaskHi Handler.\n"); 160 /* 延时2个Tick,延时后该任务会挂起,执行剩余任务中最高优先级的任务(g_taskLoID任务) */ 161 ret = LOS_TaskDelay(2); 162 if (ret != LOS_OK) { 163 PRINTK("Delay Task Failed.\n"); 164 return LOS_NOK; 165 } 166 /* 2个Tick时间到了后,该任务恢复,继续执行 */ 167 PRINTK("TaskHi LOS_TaskDelay Done.\n"); 168 /* 挂起自身任务 */ 169 ret = LOS_TaskSuspend(g_taskHiID); 170 if (ret != LOS_OK) { 171 PRINTK("Suspend TaskHi Failed.\n"); 172 return LOS_NOK; 173 } 174 PRINTK("TaskHi LOS_TaskResume Success.\n"); 175 return LOS_OK; 176} 177 178/* 低优先级任务入口函数 */ 179UINT32 ExampleTaskLo(VOID) 180{ 181 UINT32 ret; 182 PRINTK("Enter TaskLo Handler.\n"); 183 /* 延时2个Tick,延时后该任务会挂起,执行剩余任务中就高优先级的任务(背景任务) */ 184 ret = LOS_TaskDelay(2); 185 if (ret != LOS_OK) { 186 PRINTK("Delay TaskLo Failed.\n"); 187 return LOS_NOK; 188 } 189 PRINTK("TaskHi LOS_TaskSuspend Success.\n"); 190 /* 恢复被挂起的任务g_taskHiID */ 191 ret = LOS_TaskResume(g_taskHiID); 192 if (ret != LOS_OK) { 193 PRINTK("Resume TaskHi Failed.\n"); 194 return LOS_NOK; 195 } 196 PRINTK("TaskHi LOS_TaskDelete Success.\n"); 197 return LOS_OK; 198} 199/* 任务测试入口函数,在里面创建优先级不一样的两个任务 */ 200UINT32 ExampleTaskCaseEntry(VOID) 201{ 202 UINT32 ret; 203 TSK_INIT_PARAM_S initParam = {0}; 204 205 /* 锁任务调度 */ 206 LOS_TaskLock(); 207 PRINTK("LOS_TaskLock() Success!\n"); 208 /* 高优先级任务的初始化参数,其资源回收需要其他任务调用 LOS_TaskJoin */ 209 initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleTaskHi; 210 initParam.usTaskPrio = TSK_PRIOR_HI; 211 initParam.pcName = "HIGH_NAME"; 212 initParam.uwStackSize = LOS_TASK_MIN_STACK_SIZE; 213 initParam.uwResved = LOS_TASK_ATTR_JOINABLE; 214 215 /* 创建高优先级任务,由于锁任务调度,任务创建成功后不会马上执行 */ 216 ret = LOS_TaskCreate(&g_taskHiID, &initParam); 217 if (ret != LOS_OK) { 218 LOS_TaskUnlock(); 219 PRINTK("ExampleTaskHi create Failed! ret=%d\n", ret); 220 return LOS_NOK; 221 } 222 PRINTK("ExampleTaskHi create Success!\n"); 223 224 /* 低优先级任务的初始化参数,任务结束后会自行结束销毁 */ 225 initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleTaskLo; 226 initParam.usTaskPrio = TSK_PRIOR_LO; 227 initParam.pcName = "LOW_NAME"; 228 initParam.uwStackSize = LOS_TASK_MIN_STACK_SIZE; 229 initParam.uwResved = LOS_TASK_STATUS_DETACHED; 230 231 /* 创建低优先级任务,由于锁任务调度,任务创建成功后不会马上执行 */ 232 ret = LOS_TaskCreate(&g_taskLoID, &initParam); 233 if (ret!= LOS_OK) { 234 LOS_TaskUnlock(); 235 PRINTK("ExampleTaskLo create Failed!\n"); 236 return LOS_NOK; 237 } 238 PRINTK("ExampleTaskLo create Success!\n"); 239 240 /* 解锁任务调度,此时会发生任务调度,执行就绪列表中最高优先级任务 */ 241 LOS_TaskUnlock(); 242 ret = LOS_TaskJoin(g_taskHiID, NULL); 243 if (ret != LOS_OK) { 244 PRINTK("Join ExampleTaskHi Failed!\n"); 245 } else { 246 PRINTK("Join ExampleTaskHi Success!\n"); 247 } 248 while(1){}; 249 return LOS_OK; 250} 251``` 252 253编译运行得到的结果为: 254 255 256``` 257LOS_TaskLock() Success! 258ExampleTaskHi create Success! 259ExampleTaskLo create Success! 260Enter TaskHi Handler. 261Enter TaskLo Handler. 262TaskHi LOS_TaskDelay Done. 263TaskHi LOS_TaskSuspend Success. 264TaskHi LOS_TaskResume Success. 265TaskHi LOS_TaskDelete Success. 266Join ExampleTaskHi Success! 267``` 268