定位到uCOS-II/Source/os_sem.c,该文件是信号量的相关操作函数。
信号量适用于资源保护的场合,它和互斥型信号量Mutex一样,用于保护着某个共享资源,二者的差别是:Mutex是二值的(0/1),其初始值为1,某任务要操作共享资源,需要获取信号量,获取后信号量计数器为0,那么下一个任务来获取该Mutex将获取不到;而信号量Semaphore的初始值(信号量计数器)可以为大于1的数,假设为3,,那么任务A要使用该资源时,获取信号量后信号量值为2,同理,被任务B获取后信号量值为1,任务C获取后信号量值为0,那么再下一个任务来获取时就将获取不到信号量了。
1. 非阻塞的获取一个信号量函数OSSemAccept()
OSSemAccept()用于检测信号量是否可用,若资源不可用,调用此函数不会使得所在任务被挂起。
#if OS_SEM_ACCEPT_EN > 0u //定义OSSemAccept()函数使能宏
INT16U OSSemAccept (OS_EVENT *pevent) //pevent指向需要保护的共享资源的信号量
{
INT16U cnt;
#if OS_CRITICAL_METHOD == 3u //信号量中的值
OS_CPU_SR cpu_sr = 0u;
#endif
#if OS_ARG_CHK_EN > 0u //参数检测使能宏
if (pevent == (OS_EVENT *)0) {
return (0u);
}
#endif
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {
return (0u);
}
OS_ENTER_CRITICAL();
cnt = pevent->OSEventCnt; //取出信号量的值
if (cnt > 0u) { //大于0表示信号量还可以使用
pevent->OSEventCnt--; //自减表示使用了该信号量
}
OS_EXIT_CRITICAL();
return (cnt); //返回值cnt大于0表示获取信号量成功,反之获取失败
}
#endif
2. 创建信号量函数OSSemCreate()
OSSemCreate()用于创建并初始化一个信号量。
OS_EVENT *OSSemCreate (INT16U cnt) //cnt为信号量的初始值
{
OS_EVENT *pevent;
#if OS_CRITICAL_METHOD == 3u
OS_CPU_SR cpu_sr = 0u;
#endif
#ifdef OS_SAFETY_CRITICAL_IEC61508 //系统安全相关,不管
if (OSSafetyCriticalStartFlag == OS_TRUE) {
OS_SAFETY_CRITICAL_EXCEPTION();
return ((OS_EVENT *)0);
}
#endif
if (OSIntNesting > 0u) {
return ((OS_EVENT *)0);
}
OS_ENTER_CRITICAL();
pevent = OSEventFreeList; //pevent指向空闲事件链表
if (OSEventFreeList != (OS_EVENT *)0) { //如果有空余事件管理块
//空闲事件控制链表指向下一个空闲事件控制块
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
}
OS_EXIT_CRITICAL();
if (pevent != (OS_EVENT *)0) { //解引用前先判断指针是否有效
//初始化该event(信号量)的相关参数
pevent->OSEventType = OS_EVENT_TYPE_SEM;
pevent->OSEventCnt = cnt;
pevent->OSEventPtr = (void *)0; //OSEventPtr初始值为空,等到某任务获取该event后,OSEventPtr指向该任务的TCB
#if OS_EVENT_NAME_EN > 0u
pevent->OSEventName = (INT8U *)(void *)"?";
#endif
OS_EventWaitListInit(pevent); //定义在os_core.c中,实现清空该event的等待列表OSEventTbl和等待组OSEventGrp
}
re