uc/os-ii信号量

来源:互联网 发布:个人信息管理系统源码 编辑:程序博客网 时间:2024/05/08 15:40

信号量有两种类型:一种是只有0和1两种值的信号量,称为二值信号量;另一种是可以有多种值的信号量,称为计数式信号量。计数式信号量的值的大小取决于信号量的数据类型,如若是8位整型变量,则其值可以是0~255;若是16位整型变量,则其值可以是0~65 535。   
µC/OS-Ⅱ的信号量由两个部分组成:一个是信号量的计数值,范围是0~65 535;另一个是由等待该信号量的任务组成的等待任务列表。

  • 信号量可以使用在如下场合:   

    1. 允许一个任务与其它任务或中断同步;   
    2. 取得共享资源的使用权;   
    3. 标志事件的发生。
  • 对µC/OS-Ⅱ信号量初始值的赋值方法如下:   

    1. 信号量的初始值为0~65 535;
    2. 如果表示一个或者多个事件的发生,那么初始值应设为0;
    3. 如果是用于对共享资源的访问,那么该初始值应设为1。例如,把它当作二值信号量使用;
    4. 如果是用来表示允许任务访问n个相同的资源,那么该初始值应该是n,并把该信号量作为可计数的信号量使用。

µC/OS-Ⅱ提供了6种对信号量进行管理的函数,所属文件是OS_SEM.C。

这里写图片描述

  • OSSemDel()函数用于删除一个信号量,调用者只能是任务在使用OSSemDel()函数时应注意如下事项:   
    1. 由于其它函数可能还会用到这个信号量,因此在删除信号量之前,必须首先删除等待该信号量的所有任务。   
    2. 当挂起的任务进入就绪状态时,中断是关闭的,这就是说中断延迟与等待信号量的任务的数量密切相关。
    3.  opt:定义信号量删除条件的选项。它有两个选择: ① OS_DEL_NO_PEND:规定只能在已经没有任何任务等待信号量时,才能删除该信号量。 ②  OS_DEL_ALWAYS:规定不管有没有任务在等待,都立即删除这个信号量,删除后所有等待该信号量的任务立即进入就绪状态,并执行一次任务调度。
    4. 如果信号量删除成功,则返回空指针;若信号量没有能被删除,则返回pevent,这时应该检查出错代码,以查明原因。
OS_EVENT  *OSSemDel (OS_EVENT *pevent, INT8U opt, INT8U *perr){    BOOLEAN    tasks_waiting;    OS_EVENT  *pevent_return;#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */    OS_CPU_SR  cpu_sr = 0;#endif#if OS_ARG_CHK_EN > 0    if (perr == (INT8U *)0) {                              /* Validate 'perr'                          */        return (pevent);    }    if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */        *perr = OS_ERR_PEVENT_NULL;        return (pevent);    }#endif    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {        /* Validate event block type                */        *perr = OS_ERR_EVENT_TYPE;        return (pevent);    }    if (OSIntNesting > 0) {                                /* See if called from ISR ...               */        *perr = OS_ERR_DEL_ISR;                             /* ... can't DELETE from an ISR             */        return (pevent);    }    OS_ENTER_CRITICAL();    if (pevent->OSEventGrp != 0) {                         /* See if any tasks waiting on semaphore    */        tasks_waiting = OS_TRUE;                           /* Yes                                      */    } else {        tasks_waiting = OS_FALSE;                          /* No                                       */    }    switch (opt) {        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;        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;        default:             OS_EXIT_CRITICAL();             *perr                  = OS_ERR_INVALID_OPT;             pevent_return          = pevent;             break;    }    return (pevent_return);}
  • 当任务需要请求信号量时,就需要使用OSSemPend()函数。被OSSemPend()函数挂起的任务,只能被一下三种条件下回复:1. 直到有其它的任务/中断调用OSSemPost()置位信号量; 2. 信号量超出等待的预期时间; 3. 被OSSemPendAbort 恢复。如果在预期的时钟节拍内信号量被置位,那么μC/OS-Ⅱ默认最高优先级的任务取得信号量并转入就绪。
void  OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr){#if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */    OS_CPU_SR  cpu_sr = 0;#endif#if OS_ARG_CHK_EN > 0    if (perr == (INT8U *)0) {                         /* Validate 'perr'                               */        return;    }    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */        *perr = OS_ERR_PEVENT_NULL;        return;    }#endif    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type                     */        *perr = OS_ERR_EVENT_TYPE;        return;    }    if (OSIntNesting > 0) {                           /* See if called from ISR ...                    */        *perr = OS_ERR_PEND_ISR;                      /* ... can't PEND from an ISR                    */        return;    }    if (OSLockNesting > 0) {                          /* See if called with scheduler locked ...       */        *perr = OS_ERR_PEND_LOCKED;                   /* ... can't PEND when locked                    */        return;    }    OS_ENTER_CRITICAL();    if (pevent->OSEventCnt > 0) {                     /* If sem. is positive, resource available ...   */        pevent->OSEventCnt--;                         /* ... decrement semaphore only if positive.     */        OS_EXIT_CRITICAL();        *perr = OS_ERR_NONE;        return;    }                                                      /* Otherwise, must wait until event occurs       */    OSTCBCur->OSTCBStat     |= OS_STAT_SEM;           /* Resource not available, pend on semaphore     */    OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;    OSTCBCur->OSTCBDly       = timeout;               /* Store pend timeout in TCB                     */    OS_EventTaskWait(pevent);                         /* Suspend task until event or timeout occurs    */    OS_EXIT_CRITICAL();    OS_Sched();                                       /* Find next highest priority task ready         */    OS_ENTER_CRITICAL();    switch (OSTCBCur->OSTCBStatPend) {                /* See if we timed-out or aborted                */        case OS_STAT_PEND_OK:             *perr = OS_ERR_NONE;             break;        case OS_STAT_PEND_ABORT:             *perr = OS_ERR_PEND_ABORT;               /* Indicate that we aborted                      */             break;        case OS_STAT_PEND_TO:        default:                     OS_EventTaskRemove(OSTCBCur, pevent);             *perr = OS_ERR_TIMEOUT;                  /* Indicate that we didn't get event within TO   */             break;    }    OSTCBCur->OSTCBStat          =  OS_STAT_RDY;      /* Set   task  status to ready                   */    OSTCBCur->OSTCBStatPend      =  OS_STAT_PEND_OK;  /* Clear pend  status                            */    OSTCBCur->OSTCBEventPtr      = (OS_EVENT  *)0;    /* Clear event pointers                          */#if (OS_EVENT_MULTI_EN > 0)    OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;#endif    OS_EXIT_CRITICAL();}
  • OSSemPost()函数用于置位指定的信号量,或者说用于发送信号量。如果没有任务在等待信号量,那么OSSem Post()函数使该信号量加1并返回;如果有任务在等待信号量,那么最高优先级的任务将得到信号量并进入就绪状态。任务调度函数将进行任务调度,决定当前运行的任务是否仍然为最高优先级的任务。
INT8U  OSSemPost (OS_EVENT *pevent){#if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */    OS_CPU_SR  cpu_sr = 0;#endif#if OS_ARG_CHK_EN > 0    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */        return (OS_ERR_PEVENT_NULL);    }#endif    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type                     */        return (OS_ERR_EVENT_TYPE);    }    OS_ENTER_CRITICAL();    if (pevent->OSEventGrp != 0) {                    /* See if any task waiting for semaphore         */                                                      /* Ready HPT waiting on event                    */        (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK);        OS_EXIT_CRITICAL();        OS_Sched();                                   /* Find HPT ready to run                         */        return (OS_ERR_NONE);    }    if (pevent->OSEventCnt < 65535u) {                /* Make sure semaphore will not overflow         */        pevent->OSEventCnt++;                         /* Increment semaphore count to register event   */        OS_EXIT_CRITICAL();        return (OS_ERR_NONE);    }    OS_EXIT_CRITICAL();                               /* Semaphore value has reached its maximum       */    return (OS_ERR_SEM_OVF);}
0 0
原创粉丝点击