ucos 计数信号量

时间:2021-03-10 20:40:12
1:计数信号量

1.1 创建信号量
当事件控制块OS_EVENT中的OSEventType=OS_EVENT_TYPE_SEM时,则表示此处创建的事件为信号量。
ucos 计数信号量
上面为计数信号量的创建函数,创建函数不能在中断中调用,在全局的事件控制块列表中取出一个事件控制块pevent,对pevent进行初始化操作。设置此事件的类型为;OSEventType为OS_EVENT_TYPE_SEM。同时调用函数来初始化OS_EventWaitListInit()事件控制块使事件等待列表中没有等待的任务。
ucos 计数信号量
1.2 获取信号量
当某个任务获取计数信号量时,根据当前信号量的值判断此任务是继续执行还是挂起。函数
void  OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)来实现对信号量的获取。当前运行的任务不一定是系统中优先级最高的任务,只能说是在任务调度之前,就绪队列中优先级最高的任务。
ucos 计数信号量
上面的代码设置TCB的当前状态为:OS_STAT_SEM,定义如下:表示当前的任务正在等待信号量
#define  OS_STAT_SEM               0x01u    /* Pending on semaphore 
之后调用函数OS_EventTaskWait()使当前的任务添加到等待事件表中并使任务从任务就绪表中删除。
之后进行任务的调度 OS_Sched(); 任务调度之后,系统将CPU的使用权限人给就绪表中最高优先级的任务。之前看到在系统tick处理函数中进行中断级任务的调度。其有如下代码:
ucos 计数信号量
上面的代码是在函数OSTimeTick()中,在任务的等待时间不为0时if (ptcb->OSTCBDly != 0),更新任务的扥带时间及任务的就绪状态。
同时在TCB数据结构的第一次字段是:
    OS_STK          *OSTCBStkPtr;           /* Pointer to current top of stack        */
在无论是任务级还是中断及的任务切换,在切换的时候都会当前函数的指针保存在任务的堆栈中。当等待事件的任务满足等待条件或者等待超时的时候,就绪表中最高优先级的任务从自己的堆栈PC指针处继续执行。
1.3 信号量的释放
ucos 计数信号量
当对共享资源访问结束指数之后,需要对信号量进行释放操作。在对信号量计数值进行+1操作之前必须对是否还要任务等待此信号量事件进行判断。当有任务等在此信号量事件时,调用函数OS_EventTaskRdy()是任务从等待事件表中移除并使此任务进入就绪状态。
1.4 信号量的删除
OS_EVENT  *OSSemDel (OS_EVENT *pevent, INT8U opt, INT8U *perr)
上面的函数为计数信号量的删除函数,其中opt的取值如下:
opt == OS_DEL_NO_PEND   Delete semaphore ONLY if no task pending
opt == OS_DEL_ALWAYS    Deletes the semaphore even if tasks are waiting.In this case, all the tasks pending will be readied.
函数中首先判断任务等待组是否为0即可以确定是否有等待此事件的任务存在。
    if (pevent->OSEventGrp != 0) {                         /* See if any tasks waiting on semaphore    */
        tasks_waiting = OS_TRUE;                           /* Yes                                      */
    } else {
        tasks_waiting = OS_FALSE;                          /* No                                       */
    }
之后根据opt的取值分别进行处理
当opt=OS_DEL_NO_PEND 时

        case OS_DEL_NO_PEND:                               /* Delete semaphore only if no task waiting */
             if (tasks_waiting == OS_FALSE) {
#if OS_EVENT_NAME_SIZE > 1
                 pevent->OSEventName[0] = '?';             /* Unknown name                             */
                 pevent->OSEventName[1] = OS_ASCII_NUL;
#endif
                 pevent->OSEventType    = OS_EVENT_TYPE_UNUSED;
                 pevent->OSEventPtr     = OSEventFreeList; /* Return Event Control Block to free list  */
                 pevent->OSEventCnt     = 0;
                 OSEventFreeList        = pevent;          /* Get next free event control block        */
                 OS_EXIT_CRITICAL();
                 *perr                  = OS_ERR_NONE;
                 pevent_return          = (OS_EVENT *)0;   /* Semaphore has been deleted               */
             } else {
                 OS_EXIT_CRITICAL();
                 *perr                  = OS_ERR_TASK_WAITING;
                 pevent_return          = pevent;
             }
             break;
在此opt之下,之后当没有等待任务的时候才能进行此操作,将事件类型改为:
OSEventType    = OS_EVENT_TYPE_UNUSED;即此事件还没有进行赋值操作。同时将此事件控制块添加到全局的空闲控制块OSEventFreeList 链表中。
当opt=OS_DEL_ALWAYS 时,无论是否有任务等待此事件,将等待此事件的任务从等待表中删除。
        case OS_DEL_ALWAYS:                                /* Always delete the semaphore              */
             while (pevent->OSEventGrp != 0) {             /* Ready ALL tasks waiting for semaphore    */
                 (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK);
             }
#if OS_EVENT_NAME_SIZE > 1
             pevent->OSEventName[0] = '?';                 /* Unknown name                             */
             pevent->OSEventName[1] = OS_ASCII_NUL;
#endif
             pevent->OSEventType    = OS_EVENT_TYPE_UNUSED;
             pevent->OSEventPtr     = OSEventFreeList;     /* Return Event Control Block to free list  */
             pevent->OSEventCnt     = 0;
             OSEventFreeList        = pevent;              /* Get next free event control block        */

             OS_EXIT_CRITICAL();
             if (tasks_waiting == OS_TRUE) {               /* Reschedule only if task(s) were waiting  */
                 OS_Sched();                               /* Find highest priority task ready to run  */
             }

             *perr                  = OS_ERR_NONE;
             pevent_return          = (OS_EVENT *)0;       /* Semaphore has been deleted               */
             break;
同时当删除的事件有任务等待时,在进行一个任务调度。