15.2-uC/OS-III资源管理(信号量)

1.信号量

信号量是一个“ 锁定机构”,代码需要获得钥匙才可以访问共享资
源。占用该资源的任务不再使用该资源并释放资源时,其它任务才能
够访问这个资源。

通常有两种类型的信号量:二值信号量和多值信号量。

(1).二值信号量
二值信号量的值只能是 01.

(2).多值信号量

多值信号量计数值可以是 04294967295(依赖于计数值是 8位, 16位或 32位)。

特别的, uC/OS-III中的信号量计数值最大为OS_SEM_CTR(OS_TYPE.H)

根据信号量计数值,uC/OS-III可以知道有该信号量可以再被多少个任务获得。

只有任务才允许使用信号量, ISR是不允许的。

2.信号量相关的函数

函数名 功能
OSSemCreate() 创建一个信号量
OSSemDel() 删除一个信号量
OSSemPend() 等待某个信号量
OSSemPendAbort() 取消等待某个信号量
OSSemPost() 释放或标记信号量
OSSemSet() 设置信号量计数值

3信号量需注意:

 (1).用信号量访问共享资源不会导致中断延迟。当任务在执行信号量
所保护的共享资源时,
ISR或高优先级任务可以抢占该任务。

(2).应用中可以有任意个信号量用于保护共享资源。然而,推荐将信
号量用于
I/O端口的保护,而不是内存地址。

(3).信号量经常被过度使用。很多情况下,访问一个简短的共享资源
时不推荐使用信号量, 请求和释放信号量会消耗
CPU时间。 通过关/
开中断能更有效地执行这些操作。 

信号量会导致一种严重的问题:优先级反转。

4.优先级反转

优先级反转是实时系统中的一个常见问题,仅存在于基于优先级
的抢占式内核中。

1) 任务HHigh优先级) 和任务MMedium优先级) 都在
等待事件发生,任务
LLow优先级)正在被运行。
2)这时,任务L想申请信号量。
3)任务L访问共享资源。
4)任务H所等待的事件发生, uC/OS-III挂起任务L
5)开始执行任务H
6)现在任务H想要访问任务L所占用的共享资源(此时该
共享资源被任务
L占用)。因为该资源被任务L占用,任务H 被放
入挂起队列中等待这个信号量被释放。
7)任务L被恢复并继续执行。
8)任务L被任务M抢占因为任务M所等待的事件发生。
9)任务M开始执行。
10)任务M执行完毕, uC/OS-IIICPU控制权交还给任务
L

11)任务L被执行。
12)任务L执行完毕并释放资源。 此时, 任务H获得该资源,
uC/OS-III上下文切换到任务H
13)任务H开始执行。

可以看出,任务H在任务L后被执行,因为任务H等待任务L
所占用的资源。麻烦在于任务M抢占任务L,若任务M需要执行很
长时间,则任务
H会被延迟很长时间才执行,这叫做优先级反转。

解决优先级反转:

可以通过提升任务L的优先级解决这种问题(只在该任务访问共
享资源时),访问结束后就恢复任务的优先级。任务
L的优先级需要
被上升到任务
H的优先级。

5.互斥信号量mutex

uC/OS-III支持一种特殊类型的二值信号量叫做mutex,用于解决
优先级反转问题。

1)任务H和任务M等待事件的发生,任务L被执行。
2)此时,任务L申请并获得一个 mutex
3)任务L被执行。
4)任务H和任务M所等待的事件发生,任务L被抢占。
5)任务H开始执行。
6)任务H想要访问任务L占用的共享资源。考虑到任务L
占用这个资源, uC/OS-III提升任务L的优先级与任务H相同。这样
就防止了任务
L被任务M抢占(被中等优先级的任务抢占)。
7)任务L继续访问这个资源, 但现在任务L的优先级等于任

H的优先级。注意的是任务H被挂起因为它要等待任务L释放
mutex。换句话说,任务H被插入到mutex的挂起队列中。
8)任务L对共享资源的访问执行完毕并释放mutexuC/OS-III
恢复任务L到原有的优先级。然后uC/OS-III将这个mutex交给任务
H{并不是任务L已经全部执行完毕,而是当它释放信号量时就会
发生调度而转到高优先级任务
}
9)任务H开始执行。
10)任务H对共享资源的访问完毕,并释放这个mutex
11)任务H继续执行。
12)任务H执行完毕。 uC/OS-IIICPU控制权交给任务M
13) 任务M被执行。

mutex是一个内核对象,它被数据类型OS_MUTEX所定义,
(OS_MUTEX的原型是os_mutex,见OS.H)。应用中可以有任意个
mutex(仅限于处理器的RAM)。

只有任务才可以使用mutexISR不可以使用mutex)。

uC/OS-III允许任务嵌套占有mutex。如果任务获得mutex,那么
它可以嵌套获得这个
mutex多达250次。该任务需要释放相同次数才
能释放掉这个
mutex

6.与mutex相关的函数

 

函数名 功能
OSMutexCreate() 创建一个mutex
OSMutexDle() 删除一个mutex
OSMutexPend() 等待一个mutex
OSMutexPendAbort() 任务取消等待mutex
OSMutexPost() 释放mutex

任务占用共享资源前必须获得mutex。通过调用OSMutexPend()
申请这个信号量。

注意:(1).mutex是二值信号量,所以没必要初始化计数值。

(2).任何时候mutex只能提供给一个任务。 事实上, 推荐当你申请
一个
mutex时,最好不要申请其它内核对象。

7.死锁

死锁,就是两个任务互相等待对方所占用的资源的情况

可以用以下方式防止死锁:
1) 同一个时间不要申请多于一个mutex
2) 不要直接地申请mutex( 该申请放到器件驱动中和可重入函数
中)

3) 在处理之前先获得全部所需要的mutex
4) 任务间以同样的顺序申请资源
当申请信号量或
mutex时允许设置期限, 这样能防止死锁, 但是同样
的死锁可能稍后再次出现。

 

posted @ 2018-08-04 16:56  西贡小傻  Views(705)  Comments(0Edit  收藏  举报