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


信号量是什么?信号量有什么用?

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

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);                                      ;返回创建的结构体类型数据的首地址的指针

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值