您的位置:首页 > 其它

ucos II 任务间 通信之三:信号量

2015-10-14 22:46 477 查看
信号量是什么?信号量有什么用?

  
信号量一是可以用来表示一个或多个事件的发生,二是用来对共享资源的访问。

ucos II提供了5个对信号量进行操作的函数。它们是:

1. 建立一个信号量,
OSSemCreate()

2. 等待一个信号量,
OSSemPend()

3. 发送一个信号量,
OSSemPost()

4. 无等待地请求一个信号量,
OSSemAccept()

5. 查询一个信号量的当前状态,
OSSemQuery()

 

OSSemCreate()的实现代码如下:
OS_EVENT *OSSemCreate (INT16U cnt)
{
   
OS_EVENT *pevent;
 
 
   
OS_ENTER_CRITICAL();
   
pevent =
OSEventFreeList;                                         
(1)
   
if (OSEventFreeList != (OS_EVENT *)0)
{                           
(2)
       
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
   
}
   
OS_EXIT_CRITICAL();
   
if (pevent != (OS_EVENT *)0)
{                                    
(3)
       
pevent->OSEventType =
OS_EVENT_TYPE_SEM;                      
(4)
       
pevent->OSEventCnt  =
cnt;                                    
(5)
       
OSEventWaitListInit(pevent);                                  
(6)
   
}
   
return
(pevent);                                                  
(7)
}
在mcu21看来,创建一个信号量,简单来说,就是申请一个事件控制块,接着初始化这个事件控制块

首先,它从空闲任务控制块链表中得到一个事件控制块[
(1)],并对空闲事件控制链表的指针进行适当的调整,使它指向下一个空闲的事件控制块[ (2)]。如果这时有 事件 控制块可用[
(3)],就将该 事件 控制块的事件类型设置成信号量OS_EVENT_TYPE_SEM[
(4)]。其它的信号量操作函数OSSem???()通过检查该域来保证所操作的 事件控制块类型的正确。例如,这可以防止调用OSSemPost()函数对一个用作邮箱的
事件 控制块进行操作。

接着,用信号量的初始值对 事件 控制块进行初始化[(5)](如果信号量是用来表示一个或者多个事件的发生,那么该信号量的初始值应设为0,
如果信号量是用于对共享资源的访问,那么该信号量的初始值应设为1.
),并调用OSEventWaitListInit()函数对事件控制任务控制块的等待任务列表进行初始化
[(6)]。因为信号量正在被初始化,所以这时没有任何任务等待该信号量。

最后,OSSemCreate()返回给调用函数一个指向 事件 控制块的指针。以后对信号量的所有操作,如OSSemPend(),
OSSemPost(),
OSSemAccept()和OSSemQuery()都是通过该指针完成的。因此,这个指针实际上就是该信号量的句柄。如果系统中没有可用的
事件 控制块,OSSemCreate()将返回一个NULL指针


创建好一个信号之后,可以调用OSSemQuery()查询一个信号的状态。该函数有两个参数:一个是指向信号量对应事件控制块的指针pevent。;另一个是指向用于记录信号量信息的数据结构OS_SEM_DATA。

简单来说就是把信号量对应的事件控制块的信息复制到数据结构OS_SEM_DATA。

OSSemQuery()程序代码如下:
INT8U OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA
*pdata)
{
   
INT8U  i;
   
INT8U *psrc;
   
INT8U *pdest;
 
   
OS_ENTER_CRITICAL();
   
if (pevent->OSEventType != OS_EVENT_TYPE_SEM)
{      
            
(1)
       
OS_EXIT_CRITICAL();
       
return (OS_ERR_EVENT_TYPE);
   
}
   
pdata->OSEventGrp =
pevent->OSEventGrp;      
                    
(2)
   
psrc             
= &pevent->OSEventTbl[0];
   
pdest            
= &pdata->OSEventTbl[0];
   
for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
       
*pdest++ = *psrc++;
   
}
   
pdata->OSCnt     
=
pevent->OSEventCnt;      
                    
(3)
   
OS_EXIT_CRITICAL();
   
return (OS_NO_ERR);
}
OS_EVENT  *OSSemCreate (INT16U
cnt)                               
;该函数返回的数据类型为指针,指针指向的数据类型为OS_EVENT(事件的数据类型为结构体)。也就是函数返回一个地址,地址里存的是新创建的结构体类型所占据的内存的首地址。 

 OS_EVENT 
*pevent;

 pevent =
OSEventFreeList;                                                                                                                                                  
   
if (OSEventFreeList != (OS_EVENT
*)0) {               

       
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;

   
}                           

;首先创建一个指向OS_EVENT结构体类型的指针pevent;系统初始化时会创建一个空事件控制块链表,而创建的空事件控制块的数目由常数OSEventMax来决定。OSEventFreeList就指向这个空事件控制块链表的第一个,所以上面的程序里把OSEventFreeList赋给了pevent,也就是让pevent指向第一个空事件控制块,然后又让OSEventFreeList指向了空事件控制链表中的第二个。也就是从空事件链表中摘出了第一个给事件使用。

 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);           ;通过调用OSEventWaitListInit()对事件控制块中的等待任务列表进行初始化。该函数初始化一个空的等待任务列表,其中没有任何任务。该函数的调用参数只有一个,就是指向需要初始化的事件控制块的指针pevent。         

return
(pevent);                                     
;返回创建的结构体类型数据的首地址的指针
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: