rtems;:信号量管理与优先级继承
13.1: 介绍
%A
%A 信号量管理器利用Dijkstra的信号量管理算法实现信号量,为任务提供同步和互斥。 由信号量管理器提供的函数是:
%A
%A rtems_semaphore_create- 创建一个信号量
%A
%A rtems_semaphore_ident- 获取信号量的 ID标识
%A
%A rtems_semaphore_delete- 删除一个信号量
%A
%A rtems_semaphore_obtain- 获得一个信号量
%A
%A rtems_semaphore_release- 发布一个信号量
%A
%A tems_semaphore_flush- 解除因为等某个信号量而阻塞任务的阻塞态。
%A
%A
%A 13.2: 背景
%A
%A • 嵌套资源访问
%A
%A • 优先级反转
%A
%A • 优先级继承
%A
%A • 优先级高度协议
%A
%A • 构建一个信号量属性集
%A
%A • 构建一个SEMAPHORE_OBTAIN 选项集
%A
%A 一个信号量可以看成受保护的变量,他的值只能使用rtems_semaphore_create , rtems_semaphore_obtain 和 rtems_semaphore_release 函数修改。RTEMS 支援二进制信号量和计数信号量。一个二进位的信号量相当于bool变量,他的值只能是0或者1。计数信号量的值可以是一个非负整数。
%A
%A 一个二进制的信号量可以用来控制对单一资源的存取。 它通常被用于实现代码中临界段的互斥访问。在这种情况下,他的初始值是1,表示没有任务进入临界段。当任务需要进入临界段,他需要使用rtems_semaphore_obtain 函数获取信号量,信号量的值变成0,其他的任务就无法对该临界段资源进行访问。当任务退出临界段需要执行rtems_semaphore_release 函数释放信号量,这样其他任务就可以进入临界段。
%A
%A 计数号量可以控制对两个或者两个以上资源的存取。 举例来说,要访问三个打印机,就可以将计数信号量的值初始化为3,每个访问打印机的任务使用 rtems_semaphore_obtain函数获得对打印机的访问权。当计数信号量变成0,表示所有的资源都被占用,任务将等待其他任务释放打印机。当任务完成打印,它应该使用rtems_semaphore_release 函数允许其他任务访问打印机。
%A
%A 任务同步可以使用二进制信号量实现。首先将二进制信号量初始化为0。任务到达同步点如果需要和其他任务同步,就调用rtems_semaphore_obtain 函数,这时因为信号量为0,任务等待。另一个同步任务到达同步点时,可以使用rtems_semaphore_release 操作释放二进制信号量,这样保证了两个任务的同步。
%A 13.2.1: 嵌套资源访问
%A
%A 当两个任务都各自占用一个信号量,但是还需要取得对方的信号量时就会死锁(当然多个任务也会死锁,例如A占用了a,需要b;B占用了b,需要c;C占用了c需要a,就是一个死锁)。
%A
%A 一个任务对某个资源的反复需求也会造成死锁(A占用了a,在没有释放的情况下又需要使用a)。这种类型的死锁可以通过RTEMS自己解决。RTEMS中允许一个任务对某个资源的信号量反复获取(嵌套获取)。但是任务的rtems_semaphore_obtain 一定要和rtems_semaphore_release 配对。只有当最外层的信号量使用rtems_semaphore_release释放,其他任务才能获取该信号量。
%A
%A 在同步的时侯,必须使用不支持嵌套的简单二进位信号量,否则无法实现同步。
%A 13.2.2: 优先级反转
%A
%A 在RTOS 中,高优先级任务需要访问的资源被低优先级的任务占用,导致高优先级的任务被阻塞。高优先级任务必须等待低优先级任务释放资源才能唤醒。如果这个低优先级的任务还被其优先级中等的任务调度出处理器,那么反转现象还有可能进一步恶化。因为低优先级任务无法继续,导致资源无法释放,高优先级的任务可能会被无限制延迟。
%A 13.2.3: 优先级继承
%A
%A 优先级继承是一种动态提高占据互斥资源任务优先级的算法。如优先级反转一节所述,如果占据互斥资源的任务优先级变为高优先级,那么中等优先级的任务就不会抢占该任务;也就不会导致需要同一资源的其他高优先级任务因为低优先级任务而阻塞。
%A
%A RTEMS为本地的二进制信号量提供优先级继承算法。当高优先级任务因为低优先级占据资源而阻塞,那么占据资源的低优先级优先级任务的优先级将会增加。当占据资源的任务释放信号量,他的优先级将会恢复到原始状态。
%A
%A RTEMS优先级继承算法也考虑到了任务占居多个资源的信号量这一情况。此时占据资源任务的优先级将改变,新的优先级是所有阻塞任务的优先级的最小值(值越小,优先级越高)。只有当任务释放所有的信号量,他的优先级才恢复到原始水平。
%A 13.2.4: 优先级高度算法(Priority Ceiling)
%A
%A 优先级高度要求占据资源的优先级动态增加,新的优先级和所有阻塞任务中最高优先级任务的优先级相同。该算法通过一次性改变任务优先级的方式解决任务优先级反转的问题(优先级继承算法中,每次有任务阻塞就需要改变一次优先级)。优先级高度算法一次性的将任务的优先级改变提升。新的优先级是所有可能因为该资源而阻塞的任务的优先级的最小值(最高优先级Priority Ceiling)。
%A
%A RTEMS 支持本地节点上的优先级高度协议。当一个低优先级的任务获取资源的信号量,他的优先级会自动提高到优先级高度(Ceiling)的水平。该任务执行完对应的操作,释放了信号量,其优先级就会降低到原来的水平。
%A
%A 在大型系统中获取优先级高度将会很复杂。虽然优先级高度算法只用改变一次任务的优先级,所以比优先级继承算法更为高效。但是如果系统复杂,扫描将会占据信号量的所有任务同样也会降低执行效率。优先级高度算法不需要预先获取任务的相关信息,所以也显得更为灵活。
%A
%A RTEMS的优先级高度算法同样也适用于占据多个信号量的任务。 此时需要对每个二进制信号量分别进行优先级高度算法,然后获取所有优先级高度中的最高优先级(求两次最高优先级)。直到完成所有的对互斥资源的操作,他才会将优先级恢复到初始水平。
%A 13.2.5: 构建信号量属性集
%A
%A 和任务的属性集一样,信号量的属性集也是使用位运算实现的。下面是设置信号量属性集需要的各个分量:
%A
%A RTEMS_FIFO- 等待信号量的任务按照 FIFO 排序 (默认)
%A
%A RTEMS_PRIORITY- 等待信号量的任务按照优先级排序
%A
%A RTEMS_BINARY_SEMAPHORE- 信号量是二进制信号量
%A
%A RTEMS_COUNTING_SEMAPHORE- 信号量是计数信号量(默认)
%A
%A RTEMS_SIMPLE_BINARY_SEMAPHORE- 二进制信号量,并且不允许嵌套,允许对锁住的信号量进行删除操作。
%A
%A RTEMS_NO_INHERIT_PRIORITY- 不使用优先级继承 (默认)
%A
%A RTEMS_INHERIT_PRIORITY- 使用优先级继承
%A
%A RTEMS_PRIORITY_CEILING- 使用优先级高度
%A
%A RTEMS_NO_PRIORITY_CEILING- 不使用优先级高度 (默认)
%A
%A RTEMS_LOCAL- 本地任务 (默认)
%A
%A RTEMS_GLOBAL- 全局任务
%A
%A 上面的各个属性分量都是正交的单位向量。所以对他们进行或运算和进行加法操作的效果是一样的。有的分量被标明是 “ 默认 ” 表明信号量创建的时候就是用这些缺省值。所有缺省值的累加可以用向量 RTEMS_DEFAULT_ATTRIBUTES 表示。
%A
%A 例如 , 需要创建一个本地按照优先级排序的信号量 , 传给 rtems_semaphore_create 函数的 attribute_set 参数可以设置为 RTEMS_LOCAL|RTEMS_PRIORITY 。因为 RTEMS_LOCAL缺省的,所以设置为RTEMS_PRIORITY也可以。如果需要创建一个全局的按照优先级排序的信号量那么attribute_set的参数就应该使用 RTEMS_GLOBAL|RTEMS_PRIORITY 。
%A 13.2.6: 构建SEMAPHORE_OBTAIN选项集
%A
%A SEMAPHORE_OBTAIN参数设置也是使用位运算实现的。 rtems_semaphore_obtain 函数选项的各个分量在下面列出:
%A
%A RTEMS_WAIT- 如果要获取的信号量被占用,任务将会等候信号量 (默认)
%A
%A RTEMS_NO_WAIT- 任务不应该等候,这个时候任务需要自己对信号量实现轮询操作。
%A
%A 省的值可以用 RTEMS_DEFAULT_OPTIONS 表示。
%A%A
%A
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。