这里结合任哲的书籍+源代码来分析信号量
1、在任哲的书中,提到信号量只有普通的信号量,没有区分freertos所谓的二值信号量和计数信号量。可以看看源代码,ucos的代码风格是很不错的,个人认为这个风格比freertos好,看起来很舒服,不像freertos一大堆宏定义。
可以看到,OSSemCreate函数中的cnt变量如果是0,就没有资源,大于0就有资源,所以这个函数等效与freertos的二值信号量和计数信号量,一个函数就顶freertos两个函数的功能。
/* ********************************************************************************************************* * CREATE A SEMAPHORE * * Description: This function creates a semaphore. * * Arguments : cnt is the initial value for the semaphore. If the value is 0, no resource is * available (or no event has occurred). You initialize the semaphore to a * non-zero value to specify how many resources are available (e.g. if you have * 10 resources, you would initialize the semaphore to 10). * * Returns : != (void *)0 is a pointer to the event control clock (OS_EVENT) associated with the * created semaphore * == (void *)0 if no event control blocks were available ********************************************************************************************************* */ OS_EVENT *OSSemCreate (INT16U cnt) { #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr; #endif OS_EVENT *pevent; if (OSIntNesting > 0) { /* See if called from ISR ... */ return ((OS_EVENT *)0); /* ... can't CREATE from an ISR */ } OS_ENTER_CRITICAL(); pevent = OSEventFreeList; /* Get next free event control block */ if (OSEventFreeList != (OS_EVENT *)0) { /* See if pool of free ECB pool was empty */ OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; } OS_EXIT_CRITICAL(); if (pevent != (OS_EVENT *)0) { /* Get an event control block */ pevent->OSEventType = OS_EVENT_TYPE_SEM; pevent->OSEventCnt = cnt; /* Set semaphore value */ pevent->OSEventPtr = (void *)0; /* Unlink from ECB free list */ OS_EventWaitListInit(pevent); /* Initialize to 'nobody waiting' on sem. */ } return (pevent); }
重点可以看:pevent->OSEventCnt = cnt; /* Set semaphore value */
书中也有两个实例,一个是资源共享的实例,一个是同步的实例,区别在于初始化信号量的初始值是不一样的,前者是OSSemCreate(1),后者是OSSemCreate(0)。
请求信号量函数,函数原型:void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
可以看出参数中,OS_EVENT *pevent,是最重要的,如果有信号量,就会pevent->OSEventCnt--,没有就一直等待,或者等待一段时间
发送信号量函数
INT8U OSSemPost (OS_EVENT *pevent)
看得出来,参数很简单,只有一个事件的结构体指针,可以看到下面的核心语句:
if (pevent->OSEventCnt < 65535) { /* Make sure semaphore will not overflow */ pevent->OSEventCnt++; /* Increment semaphore count to register event */ OS_EXIT_CRITICAL(); return (OS_NO_ERR); }
说明,信号量是uint16类型的,发送信号量会执行pevent->OSEventCnt++
总结,就是ucos ii 2.52的代码比较易读,他的信号量已经包括了freertos的两个信号量,根据初始值不同而有所区别,其本质就是一个计数信号量的功能。