新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > μC/OS-II的任务之间的通讯与同步

μC/OS-II的任务之间的通讯与同步

作者: 时间:2016-10-08 来源:网络 收藏

值得注意的是,在μC/OS-II中,信号量一旦建立就不能删除了,因此也就不可能将一个已分配的任务控制块再放回到空闲ECB链表中。如果有任务正在等待某个信号量,或者某任务的运行依赖于某信号量的出现时,删除该任务是很危险的。

程序清单L6.9建立一个信号量

OS_EVENT*OSSemCreate(INT16Ucnt)

{

OS_EVENT*pevent;

OS_ENTER_CRITICAL();

pevent=OSEventFreeList;(1)

if(OSEventFreeList!=(OS_EVENT*)0){(2)

OSEventFreeList=(OS_EVENT*)OSEventFreeList->OSEventPtr;

}

OS_EXIT_CRITICAL();

if(pevent!=(OS_EVENT*)0){(3)

pevent->OSEventType=OS_EVENT_TYPE_SEM;(4)

pevent->OSEventCnt=cnt;(5)

OSEventWaitListInit(pevent);(6)

}

return(pevent);(7)

}

6.6.2 等待一个信号量,OSSemPend()

程序清单L6.10是OSSemPend()函数的源代码。它首先检查指针pevent所指的任务控制块是否是由OSSemCreate()建立的[L6.10(1)]。如果信号量当前是可用的(信号量的计数值大于0)[L6.10(2)],将信号量的计数值减1[L6.10(3)],然后函数将“无错”错误代码返回给它的调用函数。显然,如果正在等待信号量,这时的输出正是我们所希望的,也是运行OSSemPend()函数最快的路径。

如果此时信号量无效(计数器的值是0),OSSemPend()函数要进一步检查它的调用函数是不是中断服务子程序[L6.10(4)]。在正常情况下,中断服务子程序是不会调用OSSemPend()函数的。这里加入这些代码,只是为了以防万一。当然,在信号量有效的情况下,即使是中断服务

子程序调用的OSSemPend(),函数也会成功返回,不会出任何错误。

如果信号量的计数值为0,而OSSemPend()函数又不是由中断服务子程序调用的,则调

用OSSemPend()函数的任务要进入睡眠状态,等待另一个任务(或者中断服务子程序)发出该信

号量(见下节)。OSSemPend()允许用户定义一个最长等待时间作为它的参数,这样可以避免该

任务无休止地等待下去。如果该参数值是一个大于0的值,那么该任务将一直等到信号有效或

者等待超时。如果该参数值为0,该任务将一直等待下去。OSSemPend()函数通过将任务控制块

中的状态标志.OSTCBStat置1,把任务置于睡眠状态[L6.10(5)],等待时间也同时置入任务控

制块中[L6.10(6)],该值在OSTimeTick()函数中被逐次递减。注意,OSTimeTick()函数对每个

任务的任务控制块的.OSTCBDly域做递减操作(只要该域不为0)[见3.10节,时钟节拍]。真

正将任务置入睡眠状态的操作在OSEventTaskWait()函数中执行[见6.03节,让一个任务等待

某个事件,OSEventTaskWait()][L6.10(7)]。

因为当前任务已经不是就绪态了,所以任务调度函数将下一个最高优先级的任务调入,准备运行[L6.10(8)]。当信号量有效或者等待时间到后,调用OSSemPend()函数的任务将再一次成为最高优先级任务。这时OSSched()函数返回。这之后,OSSemPend()要检查任务控制块中的状态标志,看该任务是否仍处于等待信号量的状态[L6.10(9)]。如果是,说明该任务还没有被OSSemPost()函数发出的信号量唤醒。事实上,该任务是因为等待超时而由TimeTick()函数把它置为就绪状态的。这种情况下,OSSemPend()函数调用 OSEventTO()函数将任务从等待任务列表中删除[L6.10(10)],并返回给它的调用任务一个“超时”的错误代码。如果任务的任务控制块中的OS_STAT_SEM标志位没有置位,就认为调用 OSSemPend()的任务已经得到了该信号量,将指向信号量ECB的指针从该任务的任务控制块中删除,并返回给调用函数一个“无错”的错误代码[L6.10(11)]。

程序清单L6.10等待一个信号量

voidOSSemPend(OS_EVENT*pevent,INT16Utimeout,INT8U*err)

{

OS_ENTER_CRITICAL();

if(pevent->OSEventType!=OS_EVENT_TYPE_SEM){(1)

OS_EXIT_CRITICAL();

*err=OS_ERR_EVENT_TYPE;

}

if(pevent->OSEventCnt>0){(2)

pevent->OSEventCnt--;(3)

OS_EXIT_CRITICAL();

*err=OS_NO_ERR;

}elseif(OSIntNesting>0){(4)

OS_EXIT_CRITICAL();

*err=OS_ERR_PEND_ISR;

}else{

OSTCBCur->OSTCBStat|=OS_STAT_SEM;(5)

OSTCBCur->OSTCBDly=timeout;(6)

OSEventTaskWait(pevent);(7)

OS_EXIT_CRITICAL();

OSSched();(8)

OS_ENTER_CRITICAL();

if(OSTCBCur->OSTCBStatOS_STAT_SEM){(9)

OSEventTO(pevent);(10)

OS_EXIT_CRITICAL();

*err=OS_TIMEOUT;

}else{

OSTCBCur->OSTCBEventPtr=(OS_EVENT*)0;(11)

OS_EXIT_CRITICAL();

*err=OS_NO_ERR;

}

}

}

6.6.3 发送一个信号量,OSSemPost()

程序清单L6.11是OSSemPost()函数的源代码。它首先检查参数指针pevent指向的任务控制块是否是OSSemCreate()函数建立的[L6.11(1)],接着检查是否有任务在等待该信号量[L6.11(2)]。如果该任务控制块中的.OSEventGrp域不是0,说明有任务正在等待该信号量。这时,就要调用函数OSEventTaskRdy()[见6.02节,使一个任务进入就绪状态,OSEventTaskRdy()],把其中的最高优先级任务从等待任务列表中删除[L6.11(3)]并使它进入就绪状态。然后,调用OSSched()任务调度函数检查该任务是否是系统中的最高优先级的就绪任务[L6.11(4)]。如果是,这时就要进行任务切换[当OSSemPost()函数是在任务中调用的],准备执行该就绪任务。如果不是,OSSched()直接返回,调用 OSSemPost()的任务得以继续执行。如果这时没有任务在等待该信号量,该信号量的计数值就简单地加1[L6.11(5)]。

上面是由任务调用OSSemPost()时的情况。当中断服务子程序调用该函数时,不会发生上面的任务切换。如果需要,任务切换要等到中断嵌套的最外层中断服务子程序调用OSIntExit()函数后才能进行(见3.09节,μC/OS-II中的中断)。



关键词:

评论


相关推荐

技术专区

关闭