一.信号量
事件控制块成员OSEventType=OS_EVENT_TYPE_SEM表示信号量;信号量由信号量计数器和任务等待表两部分组成。OSEventCnt作为计数器,用OSEventTbl[]数组来充当等待任务表。
1. 当有任务申请信号量时,如果信号量计数器OSEventCnt的值大于0, 则把OSEventCnt减1并使任务继续运行。
2. 如果OSEventCnt=0,则会将任务列入任务等待表OSEventTbl[],而使任务任务处于等待状态。
3.如果正在使用信号量的任务释放了该信号量,则会在任务等待表中找出优先级别最高的等待任务,并在使它就绪后调用调度器引发一次调度;
4. 如果任务等待表中已经没有等待任务,则信号量计数器就只简单地加1。
信号量不使用事件控制块的成员OSEventPtr。
信号量的操作:
1. 创建信号量:
在使用信号量之前,应用程序必须调用函数OSSemCreate()来创建一个信号量。
函数原型:
OS_EVENT *OSSemCreate( INT16U cnt); //信号量计数器初值
返回值:已创建的信号量的指针;
2. 请求信号量
任务通过调用函数OSSemPend()请求信号量。函数原型如下:
void OSSemPend( OS_EVENT *pevent, //信号量的指针
INT16U timeout, //等待时限
INT8U *err); //错误信息
timeout是一个等待时限,是为了防止任务得不到信号量而处于长时间等待状态。超过等待时间,任务就处于就绪状态。如果timeout被设置为0, 则表明任务的等待时间为无限长。
如果任务需要访问一个共享资源时,先要请求管理该资源的信号量,这样就可以根据信号量当前是否有效来决定该任务是否可以继续运行。
1)如果信号量有效(信号量的计数器OSEventCnt的值大于0),则把信号量计数器-1,然后继续运行任务;
2)如果信号量无效(信号量的计数器OSEventCnt的值=0),则会在等待任务表中 把该任务对应的位置1而让任务处于等待状态, 并把等待时限timeout保存在任务控制块TCB的成员OSTCBDly中。
3)如果一个任务请求信号量时,如果希望在信号量无效时准许任务不进入等待状态而继续运行,则不调用函数OSSemPend(),而是调用OSSemAccept()来请求信号量。该函数原型:
INT16U OSSemAccept(OS_EVENT * pevent); //信号量的指针
3. 发送信号量
任务获得信号量,并在访问共享资源结束以后,必须释放信号量。是否信号量也叫做发送信号量。发送信号量必须调用函数OSSemPost()
函数OSSemPost()在对信号量的计数器操作之前,首先要检查是否还有等待该信号量的任务;如果没有,就把信号量计时器OSEventCnt+1,
如果有,则调用OS_Sched()调度器去运行等待任务中优先级别最高的任务。
函数原型:
INT8U OSSemnPost(OS_EVENT *pevent); //信号量的指针;
4. 删除信号量
如果应用程序不需要某个信号量,可以删除信号量用OSSemDel()来实现。
函数原型:
OS_EVENT *OSSemDel(OS_EVENT *pevent, //信号量的指针
INT8U opt, //删除条件选项
INT8U *err ); //错误信息
5. 查询信号量的状态
任务可以调用函数OSSemQuery()随时查询信号量的当前状态。
INT8U OSSemQuery(OS_EVENT *pevent, //信号量指针
OS_SEM_DATA *pdata) //存储信号量状态的结构
思考:linux中信号量的作用是为了进行进程间的同步和互斥,有PV操作等机制,那么uc/os-II是不是也遵守这个原则来进行任务间的同步和互斥?