信号量由2部分组成,一部分是16位的无符号整形信号量的计数值,另一部分是由等待该信号量的任务组成的等待任务表。信号量建立在事件的基础之上。
信号量数据结构
信号量使用事件结构,查询信号量状态时使用如下结构,包括信号量值,以及等待列表。
/*
*********************************************************************************************************
* SEMAPHORE DATA
*********************************************************************************************************
*/
#if OS_SEM_EN > 0
typedef struct os_sem_data {
INT16U OSCnt; //信号量值
#if OS_LOWEST_PRIO <= 63
INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; //等待列表组
INT8U OSEventGrp; //等待列表
#else
INT16U OSEventTbl[OS_EVENT_TBL_SIZE];
INT16U OSEventGrp;
#endif
} OS_SEM_DATA;
#endif
建立一个信号量
调用OSSemCreate函数建立信号量,并对信号量赋予初始计数值。该初始值为0-65535的一个数,如果信号量用来表示一个或多个事件的发生,那么信号量的初始值赋值为0。如果信号量用于对共享资源的访问,那么信号量的初始值应赋1。如果信号量用于允许任务同时访问n个相同的资源,那么信号量的初始值赋值为n。
OS_EVENT *OSSemCreate (INT16U cnt)
{
OS_EVENT *pevent;
#if OS_CRITICAL_METHOD == 3 //为CPU状态寄存器分配内存
OS_CPU_SR cpu_sr = 0;
#endif
if (OSIntNesting > 0) { //检查是否进入中断
return ((OS_EVENT *)0);
}
OS_ENTER_CRITICAL();
pevent = OSEventFreeList; //获取一个空闲块
if (OSEventFreeList != (OS_EVENT *)0) { //OSEventFreeList指向下一个空闲块
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
}
OS_EXIT_CRITICAL();
if (pevent != (OS_EVENT *)0) { //空闲块是否为空
pevent->OSEventType = OS_EVENT_TYPE_SEM; //设置事件为信号量类型
pevent->OSEventCnt = cnt; //设置信号量
pevent->OSEventPtr = (void *)0; //信号量该指针不使用
#if OS_EVENT_NAME_SIZE > 1
pevent->OSEventName[0] = '?'; //设置事件名为未知
pevent->OSEventName[1] = OS_ASCII_NUL;
#endif
OS_EventWaitListInit(pevent); //初始化事件为无任务等待状态
}
return (pevent);
}
删除一个信号量
首先进行各项检查,然后判断是否还有任务在等待该信号量。有两种删除信号量的方法, OS_DEL_NO_PEND,等没有任务等待时删除,如果有任务等待,返回错误,没有任务等待的话,将事件块释放。OS_DEL_ALWAYS,无论有没有事件等待都删除,直接将事件块释放,如果之前有任务等待,进行一次任务调度。
#if OS_SEM_DEL_EN > 0
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) { //检查错误指针
return (pevent);