嵌入式操作系统内核原理和开发(优先级的修改)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
之前在和rawos作者的闲聊中,rawos作者认为实时操作系统中最大的特色就是互斥量的问题。一开始,我对这个看法其实是有保留意见的,直到我看到了修改优先级的相关代码,才开始对作者的看法有了很大的认同感。实话说,在嵌入式实时系统中修改优先级是一个很复杂的事情,为什么呢,因为这其中涉及到了互斥量的问题。我们大家都知道,在嵌入式系统中优先级反转是一个绕不去的砍。低优先级的任务因为获得了互斥量因而比高优先级的任务获得了更多的运行机会,这从根本上违背了实时系统设计的初衷。所以,人们为了解决除了这一问题,提出了优先级互斥量和优先级继承两种方法。
优先级互斥量的办法比较简单,ucos也是这么做的。我们在分配一个互斥量的时候,也给这个互斥量分配一定的优先级。任何获得该互斥量的任务都会把自己的优先级修改为互斥量的优先级,这样保证了获得该优先级的任务可以在最短的时间内完成,尽快释放资源。但是,这也会导致一个问题,那就是该互斥量需要占用一个优先级,而且比此优先级高的任务也没办法获得该互斥量。另外一种方法就是优先级继承的方法,简单一点说就是任何对阻塞线程优先级的修改,都会导致拥有此互斥量的任务进行优先级的修改。闲话不多说,我们看看rawos上面的代码是怎么描述的,
RAW_U16 raw_task_priority_change (RAW_TASK_OBJ *task_ptr, RAW_U8 new_priority, RAW_U8 *old_priority)
{RAW_U8 ret_pri;RAW_U16 error;RAW_SR_ALLOC();#if (RAW_TASK_FUNCTION_CHECK > 0)if (task_ptr == 0) {return RAW_NULL_OBJECT;}if (old_priority == 0) {return RAW_NULL_OBJECT;}#endif /*Idle task is not allowed to change priority*/if (task_ptr->priority >= IDLE_PRIORITY) {return RAW_CHANGE_PRIORITY_NOT_ALLOWED;}/*Not allowed change to idle priority*/if (new_priority == IDLE_PRIORITY) { return RAW_CHANGE_PRIORITY_NOT_ALLOWED;}RAW_CRITICAL_ENTER();#if (CONFIG_RAW_MUTEX > 0)ret_pri = chg_pri_mutex(task_ptr, new_priority, &error);if (error != RAW_SUCCESS) {goto error_exit;}task_ptr->bpriority = new_priority;new_priority = ret_pri;#elsetask_ptr->bpriority = new_priority;#endif*old_priority = task_ptr->priority;error = change_interal_task_priority(task_ptr, new_priority);if (error != RAW_SUCCESS) {goto error_exit;}RAW_CRITICAL_EXIT();do_possible_sche(); return RAW_SUCCESS;error_exit:RAW_CRITICAL_EXIT();return error;}
这个函数是系统本身提供的一个函数,内容不算少,但是重点可以放在两个子函数上面。一个部分是函数chg_pri_mutex,另外一个函数是change_interal_task_priority。前者判断当前优先级是否可以修改,后者判断如何对当前的任务进行修改,后面我们会看到会对这个问题有一个详细的说明。
RAW_U8 chg_pri_mutex(RAW_TASK_OBJ *tcb, RAW_U8 priority, RAW_U16 *error)
{RAW_MUTEX *mtxcb;RAW_U8 hi_pri, low_pri, pri;RAW_TASK_OBJ *first_block_task;LIST *block_list_head;hi_pri = priority;low_pri = 0;mtxcb = (RAW_MUTEX *)(tcb->block_obj);if (mtxcb) {/*if it is blocked on mutex*/if (mtxcb->common_block_obj.object_type == RAW_MUTEX_OBJ_TYPE) {if (mtxcb->policy == RAW_MUTEX_CEILING_POLICY) {pri = mtxcb->ceiling_prio;if (pri > low_pri) {low_pri = pri;}}}}/* Locked Mutex */pri = hi_pri;for (mtxcb = tcb->mtxlist; mtxcb != 0; mtxcb = mtxcb->mtxlist) {switch (mtxcb->policy) {case RAW_MUTEX_CEILING_POLICY:pri = mtxcb->ceiling_prio;if ( pri > low_pri ) {low_pri = pri;}break;case RAW_MUTEX_INHERIT_POLICY:block_list_head = &mtxcb->common_block_obj.block_list;if (!is_list_empty(block_list_head)) {first_block_task = list_entry(block_list_head->next, RAW_TASK_OBJ, task_list); pri = first_block_task->priority;}break;default:/* nothing to do */break;}if ( pri < hi_pri ) {hi_pri = pri;}}if (priority < low_pri) {*error = RAW_EXCEED_CEILING_PRIORITY;return RAW_EXCEED_CEILING_PRIORITY;}*error = RAW_SUCCESS;return hi_pri;
}
上面的代码还是比较复杂的,我们看到其实任务的优先级不是可以随便修改的,因为当前任务可能已经占有了许多互斥量资源,而这些互斥量资源其实是有约束条件的。如果占有的互斥量类型是那种带优先级的互斥量,那么必须找出的那个最低优先级的互斥量,至少修改的任务优先级不能比它高。剩下的工作就是在继承优先级的体制下寻找到最高的优先级,仅此而已。
RAW_U16 change_interal_task_priority(RAW_TASK_OBJ *task_ptr, RAW_U8 new_priority)
{RAW_U8 old_pri;switch (task_ptr->task_state) {case RAW_RDY:remove_ready_list(&raw_ready_queue, task_ptr);task_ptr->priority = new_priority;if (task_ptr == raw_task_active) {add_ready_list_head(&raw_ready_queue, task_ptr);}else {add_ready_list_end(&raw_ready_queue, task_ptr);}break;case RAW_DLY: /* Nothing to do except change the priority in the OS_TCB */case RAW_SUSPENDED:case RAW_DLY_SUSPENDED:task_ptr->priority = new_priority; /* Set new task priority*/break;case RAW_PEND:case RAW_PEND_TIMEOUT:case RAW_PEND_SUSPENDED:case RAW_PEND_TIMEOUT_SUSPENDED:old_pri = task_ptr->priority;task_ptr->priority = new_priority; change_pend_list_priority(task_ptr);#if (CONFIG_RAW_MUTEX > 0)mtx_chg_pri(task_ptr, old_pri);#endifbreak;default:#if (CONFIG_RAW_ASSERT > 0)RAW_ASSERT(0);#endifreturn RAW_STATE_UNKNOWN;}return RAW_SUCCESS;}
前面,我们说到了优先级的修改函数,而change_interal_task_priority就是完成这一功能的函数。当然,我们需要针对目前任务的状态对任务的优先级进行修改,如果任务此时正在运行或者延迟运行,那么还好办,关键是如果此时任务已经阻塞了,那么考虑的情况就多了。
RAW_VOID mtx_chg_pri(RAW_TASK_OBJ *tcb, RAW_U8 oldpri)
{RAW_MUTEX *mtxcb;RAW_TASK_OBJ *mtxtsk;mtxcb = (RAW_MUTEX *)(tcb->block_obj);if (mtxcb->common_block_obj.object_type == RAW_MUTEX_OBJ_TYPE) {if (mtxcb->policy == RAW_MUTEX_INHERIT_POLICY) {mtxtsk = mtxcb->mtxtsk;if (mtxtsk->priority > tcb->priority) {/* Since the highest priority of the lock wait taskbecame higher, raise the lock get task priorityhigher */change_interal_task_priority(mtxtsk, tcb->priority);}/*the highest priority task blocked on this mutex may decrease priority so reset the mutex task priority*/else if(mtxtsk->priority == oldpri) {release_mutex(mtxtsk, 0);}}}}
mtx_chg_pri函数此时考虑的不光是它自己优先级的问题,它还需要考虑此时占有互斥量的这个任务优先级该怎么修改。我们进一步看看release_mutex下面做了哪些工作。
static RAW_VOID release_mutex(RAW_TASK_OBJ *tcb, RAW_MUTEX *relmtxcb)
{RAW_MUTEX *mtxcb, **prev;RAW_U8 newpri, pri;RAW_TASK_OBJ *first_block_task;LIST *block_list_head;/* (B) The base priority of task */newpri = tcb->bpriority;/* (A) The highest priority in mutex which is locked */pri = newpri;prev = &tcb->mtxlist;while ((mtxcb = *prev) != 0) {if (mtxcb == relmtxcb) {/* Delete from list */*prev = mtxcb->mtxlist;continue;}switch (mtxcb->policy) {case RAW_MUTEX_CEILING_POLICY:pri = mtxcb->ceiling_prio;break;case RAW_MUTEX_INHERIT_POLICY:block_list_head = &mtxcb->common_block_obj.block_list;if (!is_list_empty(block_list_head)) {first_block_task = list_entry(block_list_head->next, RAW_TASK_OBJ, task_list); pri = first_block_task->priority;}break;default:break;}if (newpri > pri) {newpri = pri;}prev = &mtxcb->mtxlist;}if ( newpri != tcb->priority ) {/* Change priority of lock get task */change_interal_task_priority(tcb, newpri);}}
这个函数的工作就是修改那个获得互斥量的任务的优先级的,在寻找到最高优先级之后,那么又需要调用change_internall_task_priority函数了。有过递归函数编写经验的朋友就知道了,这其实就是一个典型的递归函数。change_internall_task_priority函数调用到release_mutex,然而release_mutex又调用到change_internall_task_priority,感觉上没完没了了,其实不是这样。递归函数都是需要出口的,这个函数的出口就是change_internall_task_priority,一切等到获得的那个任务不再是阻塞任务为止,整个修改的过程就结束了。当然,任务优先级恢复的工作也是非常麻烦的,不管是带优先级的互斥量还是优先级继承机制的互斥量,额外的优先级修改和计算都是必须的,不知道我讲清楚了没有。rawos在互斥量的最大进步就是进一步说明了拥有多互斥量的任务该如何修改优先级,当然了,函数迭代的过程多了堆栈使用的空间也多了,有没有溢出的危险,这是我们需要考虑的另外一个重要因素。
嵌入式操作系统内核原理和开发(优先级的修改)相关推荐
- 嵌入式操作系统内核原理和开发
嵌入式操作系统内核原理和开发(开篇) 操作系统是很多人每天必须打交道的东西,因为在你打开电脑的一刹那,随着bios自检结束,你的windows系统已经开始运行了.如果问大家操作系统是什么?可能有的人会 ...
- 嵌入式操作系统内核原理和开发(总结篇)
[ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 很多朋友都喜欢嵌入式操作系统的内容,但是如何实现和仿真这样一个系统一直是困扰我们的难题.现在郑 ...
- 嵌入式操作系统内核原理和开发(地址空间)
[ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 不管是什么样的嵌入式cpu,它必然有自己的访问地址空间.至于这个具体的访问空间是什么,那cpu ...
- 嵌入式操作系统内核原理和开发(实时系统中的定时器)
[ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 关于定时器的内容,其实我们之前也讨论过,也书写过相应的代码,但是表达得比较晦涩,效率也比较低. ...
- 嵌入式操作系统内核原理和开发(消息队列)
[ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 消息队列是线程交互的一种方法,任务可以通过消息队列来实现数据的沟通和交换.在嵌入式系统上,这可 ...
- 嵌入式操作系统内核原理和开发(信号量)
[ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 之前因为工作的原因,操作系统这块一直没有继续写下去.一方面是自己没有这方面的经历,另外一方面就 ...
- 嵌入式操作系统内核原理和开发(头文件调整)
[ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 很长一段时间,我个人对头文件的功能了解得不是很明白.虽然在平时的开发中,对于头文件也没有犯过什 ...
- 嵌入式操作系统内核原理和开发(任务创建和堆栈溢出检查)
[ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 虽然写操作系统的博客要比写普通的技术点要麻烦一些,但是心中还是挺开心的.一方面,通过几行代码就 ...
- 嵌入式操作系统内核原理和开发(基础)
[ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 在编写我们的操作系统之前,我们需要明确一些事情.比如说,这个系统的运行环境是什么?怎么编译?基 ...
最新文章
- iOS更改AppIcon
- 三、Spring Boot在org.springframework.boot组下应用程序启动器
- 推荐3个C++系统项目!初级开发者必学!
- js操作json方法总结
- 查看 linux 网络状态命令,Linux操作系统常用的网络状态查询命令
- “霸王级”寒潮来袭 通信业紧急部署确保网络安全
- cocos2d-x 关于无法找到gl/gl.h头文件错误,以及r.java无法生成解决办法
- PHP+jQuery.photoClip.js支持手势的图片裁剪上传实例
- VC2008中影响exe大小和速度的全部编译选项
- 游戏测试用例及游戏测试bug详解
- Android 屏幕适配tips
- makefile 指定文件搜索路径和文件生成路径
- Altium Designer原理图标题栏显示参数的解决方法
- 加拿大电子计算机工程留学,【加中留学】加拿大计算机工程专业哪些大学比较好...
- 如何在 JavaScript 中使用对象解构
- 微信公众号花式排版技巧分享
- 矢志不渝为安全—清华同方举安全大旗正式杀入云计算市场
- linux命令查询端口号,linux查询端口号(linux查看端口的命令)
- Android获取一周每一天的日期
- 【问题解决】电脑能用QQ但是打不开网页
热门文章
- VC++ 在两个程序中 传递字符串等常量值的方法:使用了 WM_COPYDATA 消息的
- js中substr与substring的差别
- ArnetMiner – A Review
- Windows 7 ship party
- 用C++开发与调用WebService的例子
- 一个销售精英拜访客户的6大绝招,胜过10次培训,实用!
- 文件操作命令(replace)
- HDU_oj_2046 骨牌铺方格
- 通讯框架 t-io 学习——给初学者的Demo:ShowCase设计分析
- elasticsearch的rest搜索--- 查询