MyException - 我的异常网
当前位置:我的异常网» 操作系统 » 嵌入式操作系统内核原理跟开发(优先级的修改)

嵌入式操作系统内核原理跟开发(优先级的修改)

www.myexceptions.net  网友分享于:2013-11-08  浏览:6次
嵌入式操作系统内核原理和开发(优先级的修改)

 

【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱: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;
	
	#else
	
	task_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);
			#endif
			
			break;

		default:
			
			#if (CONFIG_RAW_ASSERT > 0)
			RAW_ASSERT(0);
			#endif
			
			return 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 task
		  		 became higher, raise the lock get task priority
		   		higher */
				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在互斥量的最大进步就是进一步说明了拥有多互斥量的任务该如何修改优先级,当然了,函数迭代的过程多了堆栈使用的空间也多了,有没有溢出的危险,这是我们需要考虑的另外一个重要因素。


 

 

 

文章评论

程序员的鄙视链
程序员的鄙视链
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
代码女神横空出世
代码女神横空出世
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
我是如何打败拖延症的
我是如何打败拖延症的
中美印日四国程序员比较
中美印日四国程序员比较
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
旅行,写作,编程
旅行,写作,编程
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
漫画:程序员的工作
漫画:程序员的工作
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
我的丈夫是个程序员
我的丈夫是个程序员
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
编程语言是女人
编程语言是女人
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
每天工作4小时的程序员
每天工作4小时的程序员
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
鲜为人知的编程真相
鲜为人知的编程真相
10个调试和排错的小建议
10个调试和排错的小建议
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
程序员和编码员之间的区别
程序员和编码员之间的区别
老程序员的下场
老程序员的下场
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
如何成为一名黑客
如何成为一名黑客
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
那些争议最大的编程观点
那些争议最大的编程观点
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
 程序员的样子
程序员的样子
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
程序员必看的十大电影
程序员必看的十大电影
总结2014中国互联网十大段子
总结2014中国互联网十大段子
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
一个程序员的时间管理
一个程序员的时间管理
程序员应该关注的一些事儿
程序员应该关注的一些事儿
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有