创建任务的过程,首先分配一个空闲的TCB给任务,然后对该TCB的各个域进行赋值,对任务的堆栈进行初始化,其中,任务的代码的地址被压入堆栈。这为以后任务的运行做了充分准备。就绪表和就绪组做了适当的处理,根据任务的优先级进行了设置。就绪TCB链表也插入了该TCB。
那么若将任务删除,就是任务创建的逆过程,应该将就绪表、就绪组进行逆向操作,就绪链表中的相关TCB应该被移除,转移到空闲TCB链表。和任务创建一样,也要进行一些检查,看任务是否符合被删除的条件。
任务删除还设计一个请求删除的问题,因此任务删除看似简单,实际上是比较复杂的一个过程。
任务删除函数的参数只有一个,这个参数就是任务的优先级。我们知道,任务的优先级是μC/OS-II标志任务的唯一标志,任务控制块中虽然也有一个ID,但只是为了扩展使用。因此,任务删除函数也可以理解为删除指定优先级的任务。
由于任务删除的代码很长,而在执行的过程中一直在访问全局变量,因此使系统不能响应中断,破坏系统的实时性。因此,在代码的中间,使用巧妙的手段来开一次中断,过程如下:
1)将任务调度锁加1
2)开中断
3)执行一条空语句保证中断有时间执行
4)关中断
5)将调度锁减1,恢复原来的值。
这一段代码几乎是μC/OS-II中最复杂的一段代码,理解它需要有足够的耐心。
当以其他任务的优先级作为参数的时候,OSTaskDel粗暴地删除了任务,这在某些情况下是有效的,但是却不是必须这么做。通知对方任务,告诉它要被删除了,请任务自己删除自己是一种更好的做法。因为这么做,任务可以在删除自己之前先放弃自己使用的资源,如缓冲区、信号量、邮箱、队列等。如果总是用
OSTaskDel删除一个任务,这个任务占用的资源不能得到释放,系统就会产生内存泄露,在内存泄露累积到比较大的时候,系统就会因为没有可用的内存而崩溃。
其实
OSTaskDelReq名称虽然是请求,却是集请求与响应于一段代码内,改代码的功能时请求删除某任务和查看是否有任务要删除自己。
例如,优先级为5的任务A调用
OSTaskDelReq
(10),请求删除优先级为10的任务B。任务B调用
OSTaskDelReq(OS_PRIO_SEL)并查看返回值,如果返回值为OS_ERR_TASK_DEL_REQ,说明有任务要删除自己了。任务B应该先释放自己使用的资源,然后调用
OSTaskDel(10)或
OSTaskDel(
OS_PRIO_SEL
)来删除自己。