信号量管理-等待一个信号量,OSSemPend()函数见解

时间:2022-03-29 20:40:21

等待一个信号量,OSSemPend()

该函数用于任务试图取得设备的使用权、任务需要和其他任务或中断同步、任务需要等待特定事件的发生的场合。(初学者见解,欢迎指正)

如果任务调用OSSemPend() 函数时,信号量的值大于零,OSSemPend() 函数递减该值并返回该值。如果调用时信号量值等于零,OSSemPend() 函数将任务加入该信号量的等待队列。OSSemPend() 函数挂起当前任务直到其他的任务或中断设置信号量或超出等待的预期时间。如果在预期的时钟节拍内信号量被设置,μC/OS-Ⅱ默认让最高优先级的任务取得信号量并回到就绪状态。一个被OSTaskSuspend() 函数挂起的任务也可以接受信号量,但这个任务将一直保持挂起状态直到通过调用OSTaskResume() 函数恢复该任务的运行。

任务Task_A调用OSSemPend(),且信号量的值有效(非0),那么OSSemPend()递减信号量计数器(.OSEventCnt),并返回该值。换句话说,Task_A获取到共享资源的使用权了,之后就执行该资源。如果如果任务Task_A调用OSSemPend(),信号量无效(为0),那么OSSemPend()调用OS_EventTaskWait()函数,把Task_A放入等待列表中。(等待到什么时候呢?要看OSSemPost()(或者等待超时情况),由它释放信号量并检查任务执行权)

函数原型:void OSSemPend ( OS_EVNNT *pevent, INT16U timeout, int8u *err );
参数说明:pevent 是指向信号量的指针。该指针的值在建立该信号量时可以得到。(参考OSSemCreate() 函数)。
         timeout 允许一个任务在经过了指定数目的时钟节拍后还没有得到需要的信号量时恢复就绪状态。如果该值为零表示任务将持续地等待信号量,最大的等待时间为65535个时钟节拍。这个时间长度并不是非常严格的,可能存在一个时钟节拍的误差。
         err 是指向包含错误码的变量的指针,返回的错误码可能为下述几种:
            * OS_NO_ERR :信号量不为零。
            * OS_TIMEOUT :信号量没有在指定数目的时钟周期内被设置。
            * OS_ERR_PEND_ISR :从中断调用该函数。虽然规定了不允许从中断调用该函数,但μC/OS-Ⅱ仍然包含了检测这种情况的功能。
            * OS_ERR_EVENT_TYPE :pevent 不是指向信号量的指针。
返回值:无

/ PEND ON SEMAPHORE

* Description: This function waits for a semaphore.

* Arguments :

pevent   is a pointer to the event control block associated with the desired semaphore.

timeout   is an optional timeout period (in clock ticks). If non-zero, your task will wait for the resource up to the amount of time specified by this argument. If you specify 0, however, your task will wait forever at the specified semaphore or, until the resource becomes available (or the event occurs).

err   is a pointer to where an error message will be deposited. Possible error messages are:

OS_NO_ERR The call was successful and your task owns the resource or, the event you are waiting for occurred.

OS_TIMEOUT   The semaphore was not received within the specified timeout.

OS_ERR_EVENT_TYPE   If you didn't pass a pointer to a semaphore.

OS_ERR_PEND_ISR   If you called this function from an ISR and the result would lead to a suspension.

OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.

* Returns    : none

*/

void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

    OS_CPU_SR cpu_sr;

#endif  

    if (OSIntNesting > 0) { /* See if called from ISR ... */

        *err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */

        return;

    }

#if OS_ARG_CHK_EN > 0 /*OS_ARG_CHK_EN Enable (1) or Disable (0) argument checking */

    if (pevent == (OS_EVENT *)0) {   /* Validate 'pevent' 依靠是否指针为空判断指针是否指向链表以外*/

        *err = OS_ERR_PEVENT_NULL;

        return;

    }

    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type              判断事件控制块的事件类型是否为信号量*/

        *err = OS_ERR_EVENT_TYPE;

        return;

    }

#endif

    OS_ENTER_CRITICAL();

    if (pevent->OSEventCnt > 0) { /* If sem. is positive, resource available ... 递减信号量计数器(.OSEventCnt),并返回该值。换句话说,获取到共享资源的使用权了,之后就执行该资源。 */

        pevent->OSEventCnt--; /* ... decrement semaphore only if positive. */

       OS_EXIT_CRITICAL();

        *err = OS_NO_ERR;

        return; /*退出当前执行的函数体,如果这个函数是有返回值的就返回相应的类型值,没有返回值的就返回空;同时也把控制权交还给主调函数*/

    }

/* Otherwise, must wait until event occurs */

OSTCBCur->OSTCBStat |= OS_STAT_SEM;   /* Resource not available, pend on semaphore ; #define OS_STAT_SEM 0x01   Pending on semaphore ; OSTCBStat 任务状态字 */

    OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */

    OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs是当前任务从就绪任务表中脱离就绪状态,并放到相应事件的事件控制块ECB的等待任务表中*/

    OS_EXIT_CRITICAL();

    OS_Sched(); /* Find next highest priority task ready 调度任务调度函数让下一个优先级最高的任务运行。而调用OSSemPend()函数的任务被挂起(OS_EventTaskWait()完成了这一步),一直等待相应的信号量出现,才可以继续运行。另外,需要认真查看函数OS_Sched(),这关系到该OSSemPend()函数的关键部分。注意对任务控制块中状态标志的影响*/

    OS_ENTER_CRITICAL();

    if (OSTCBCur->OSTCBStat & OS_STAT_SEM) { /* Must have timed out if still waiting for event 检查任务控制块中的状态字OSTBStat是否处于信号量的等待状态。*/

        OS_EventTO(pevent); /*因为等待超时而将等待的任务置为就绪状态*/

        OS_EXIT_CRITICAL();

        *err = OS_TIMEOUT; /* Indicate that didn't get event within TO*/

        return;

    }

    OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;

    OS_EXIT_CRITICAL();

    *err = OS_NO_ERR;

}



原帖地址 http://hi.baidu.com/daysummary/item/769bad17ad5f5403d0d66d01