1.任务的挂起(任务进入挂起态,相当于任务运行所需的某事件、条件不满足,任务被暂停了,无法继续运行)
a)有些时候任务必须等待某些事件发生,若事件还未发生时,任务就会设置为挂起状态。
b)挂起状态的任务被放置在挂起列表中以标明任务在等待某些事件的发生。等待的时候,任务是不会占用CPU的。事件发生时,改任务会被放到就绪队列中。在这种情况下,正在运行的任务可能会被抢占(被放回就绪列表),并由UCOSiii选择优先级最高的任务去运行。换句话说,如果新的任务优先级最高,那么它就会被立即运行。
c)任务挂起函数:OS_TaskSuspend();
d)任务恢复函数:OS_TaskResume();
e)调用OSTaskSuspend()会任务无条件地停止运行。有时候调用OSTaskSuspend()不是为了等待某个事件的发生,而是等待另外一个任务调用OSTaskResume()函数恢复这个任务。
f)恢复任务时,不同任务的优先级会很大程度上影响任务的运行顺序。
注意:一个任务可以被多次挂起,但是被n次挂起之后就必须要对改任务恢复n次才可以
2.资源管理
a)共享资源可以是:变量(静态的或全局的)、结构体、内存空间、IO等。
b)多个任务可能会同时要求占用共享资源:内存空间、全局变量、指针、缓冲区、列表、环形缓冲区等。也通过共享资源,来达到任务之间的通信。当然,避免任务间的竞争和防止资源破坏是非常重要的。
c)保护共享资源的方式:
i关闭中断:(独占共享资源的最快和最简单方法)
void YourFunction(void)
{
CPU_SR_ALLOC(); (1)
CPU_CRITICAL_ENTER(); (2)
Access the resource; (3)
CPU_CRITICAL_EXIT(); (4)
}
(2)中CPU_CRITICAL_ENTER()关全局中断。
(3中 Access the resource; 访问临界段时不会被中断或任务打断,因为中断被关闭。换句话说,临界段的操作是原子性。
(4中CPU_CRITICAL_EXIT()从这个本地变量中恢复关中断前的CPU状态,并开全局中断。
3.信号量
1.)信号量是一个“锁定机构”(当作一把锁,锁住共享资源),代码需要获得钥匙才可以访问共享资源。占用该资源的任务不再使用该资源并释放资源时,其它任务才能够访问这个资源。
2.)通常有两种类型的信号量:二值信号量和多值信号量。二值信号量的值只能是0或1(相当于钥匙的有无)。多值信号量计数值可以是0到4294967295;
3.)只有任务才允许使用信号量,ISR是不允许的。
4.)互斥信号量(mutex)
a)UCOSiii支持一种特殊类型的二值信号量叫做mutex,用于解决优先级反转问题。
b)互斥信号量可以被嵌套,因此,任务可申请同一个互斥信号量多达250次。
5.)各个方式之间的区别
采用哪种机制决定于访问共享资源的代码长度
4.解决优先级反转问题:
a)如果mutex已被更低优先级任务占用,UCOSiii会提升更低优先级任务的优先级与要使用共享资源任务的优先级相同。
F13-5(1)任务H和任务M等待事件的发生,任务L被执行。
F13-5(2)此时,任务L申请并获得一个mutex。
F13-5(3)任务L被执行。
F13-5(4)任务H和任务M所等待的事件发生,任务L被抢占。
F13-5(5)任务H开始执行。
F13-5(6)任务H想要访问任务L占用的共享资源。考虑到任务L占用这个资源,uC/OS-III提升任务L的优先级与任务H相同。这样就防止了任务L被任务M抢占(被中等优先级的任务抢占)。
F13-5(7)任务L继续访问这个资源,但现在任务L的优先级等于任务H的优先级。注意的是任务H被挂起因为它要等待任务L释放mutex。换句话说,任务H被插入到mutex的挂起队列中。
F13-5(8)任务L对共享资源的访问执行完毕并释放mutex。uC/OS-III恢复任务L到原有的优先级。然后uC/OS-III将这个mutex交给任务H。{并不是任务L已经全部执行完毕,而是当它释放信号量时就会发生调度而转到高优先级任务}
F13-5(9)任务H开始执行。
F13-5(10)任务H对共享资源的访问完毕,并释放这个mutex。
F13-5(11)任务H继续执行。
F13-5(12)任务H执行完毕。uC/OS-III将CPU控制权交给任务M。
F13-5(13)任务M被执行。现在没有优先级反转的问题了。当然,任务L占用共享资源的时间越短越好。
b)如果其它高优先级任务已经占用这个mutex,要使用共享资源,任务调用“pend”函数为OS_OPT_PEND_BLOCKING模式(阻塞等待)时,它会被放入挂起队列直到mutex被释放。
c)为什么需要检查获取互斥锁函数OSMutexpend()的返回值呢,有以下四种可能:
1)任务获得mutex;
2)在使用mutex中的等待任务被其它任务取消等待;
3)等待超时;
4)这个mutex被删除;
可以通过OSMuterpend()函数返回的错误码知道改函数的执行情况。
注意:任何时候mutex被哪个任务申请,就要被哪个任务释放,不然会造成死锁。