UCOSII学习之路2 任务同步之信号量的使用

本文介绍了UCOSII操作系统中任务同步的重要机制——信号量,包括信号量的概念、作用以及如何通过事件控制块进行同步。通过解析信号量的结构和操作函数,阐述了信号量在多任务共享资源时如何实现高效通信和任务调度。同时,讨论了在实际应用中理解信号量运作原理的重要性。
摘要由CSDN通过智能技术生成

    注:以下讨论都是基于UCOSII V2.92.07,其他版本可能略微存在差异。

引用任哲书上的一句话解释什么是信号量最合适不过,应用程序中的各个人物,必须通过彼此之间的有效合作,才能完成一项大规模的工作,因为这些任务在运行的时候,经常需要无冲突的访问同一个共享资源,或者需要互相支持和依赖,甚至有时还要相互制约才能保证任务的顺利运行,因此操作系统必须具有对任务运行进行协调的能力,从而使任务无冲突、流畅的同步运行,这就是为什么我们要使用任务间同步机制。

谈到任务的同步,UCOSII中一共有4种同步方式。(信号量、互斥信号量、消息邮箱、消息队列)而要想深入理解这一系列的机制。那免不了说说他们的基本组成单元(事件控制块),我们通过几幅图片来理解一下。


通过上面的图片来理解信号量是不是比较直观。不过开始也就让大家有个印象,接下来说说任务同步的基本组成-事件控制块。

事件控制块:
事件控制块的基本数据结构


	typedef struct os_event {
	    INT8U    OSEventType;       //说明具体的同步机制类型,如消息邮箱            
	    void    *OSEventPtr;        //未使用时用于链接控制块为单向链表,使用时根据具体情况使用
	    INT16U   OSEventCnt;        
	    OS_PRIO  OSEventGrp;          //事件组           
	    OS_PRIO  OSEventTbl[OS_EVENT_TBL_SIZE]; //事件标志,主要存放等待相应信号的任务标志 

	#if OS_EVENT_NAME_EN > 0u
	    INT8U   *OSEventName; //事件名
	#endif
	} OS_EVENT;

 

而在一开始,事件控制块会被系统初始化为一个单向的链表。


上面就是一个基本的事件控制块结构,他是组成其他同步机制的基础。而关于其基本的操作函数,也

有3个。
分别为
void  OS_EventWaitListInit (OS_EVENT *pevent); //初始化一个事件控制块
void  OS_EventTaskWait (OS_EVENT *pevent);   //使一个任务进入等待某事件发生的状态
INT8U  OS_EventTaskRdy (OS_EVENT  *pevent, void      *pmsg,
                        INT8U      msk, INT8U      pend_stat); //使一个任务进入就绪态
  //  void OS_EventTO(OS_EVENT *pevent); //等待超时而将任务置于就绪态 在V2.53版本中存在
void  OS_EventTaskRemove (OS_TCB   *ptcb, OS_EVENT *pevent) //V2.9版本,其作用和OS_EventTO()相同
    
    接下来我们来分析分析这四个函数的具体实现

void  OS_EventWaitListInit (OS_EVENT *pevent)
	{
	    INT8U  i;
	    pevent->OSEventGrp = 0u;                    //初始化传进来的时间控制块OSEventGrp域为0
	    for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) {
	        pevent->OSEventTbl[i] = 0u;     //初始化对应的标志数组
	    }
	}
总而言之是对OS_EVENT事件控制块域的初始化。

void  OS_EventTaskWait (OS_EVENT *pevent)
	{
	    INT8U  y;

	    OSTCBCur->OSTCBEventPtr               = pevent;  //保存任务的事件控制块指针      
	    pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;//置起当前任务到等待事件表
	    pevent->OSEventGrp                   |= OSTCBCur->OSTCBBitY;

	    y             =  OSTCBCur->OSTCBY;            /* Task no longer ready                              */
	    OSRdyTbl[y]  &= (OS_PRIO)~OSTCBCur->OSTCBBitX;
	    if (OSRdyTbl[y] == 0u) {                      //如果任务没有就绪,则清除标志组
	        OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
	    }
	}
其主要是将调用本函数的任务挂起,具体挂起的类型主要看该控制块的数据类型

	INT8U  OS_EventTaskRdy (OS_EVENT  *pevent,
                        void      *pmsg,
                        INT8U      msk,
                        INT8U      pend_stat)
	{
	    OS_TCB   *ptcb;
	    INT8U     y;
	    INT8U     x;
	    INT8U     prio;
	#if OS_LOWEST_PRIO > 63u
	    OS_PRIO  *ptbl;
	#endif


	#if OS_LOWEST_PRIO <= 63u
	    y    = OSUnMapTbl[pevent->OSEventGrp];              /* Find HPT waiting for message                */
	    x    = OSUnMapTbl[pevent->OSEventTbl[y]];
	    prio = (INT8U)((y << 3u) + x);                 //获取当前挂起的最高优先级任务
	#else
	    if ((pevent->OSEventGrp & 0xFFu) != 0u) {       //当最低优先级大于63时,启用16*16事件标志组
	        y = OSUnMapTbl[ pevent->OSEventGrp & 0xFFu];
	    } else {
	        y = OSUnMapTbl[(OS_PRIO)(pevent->OSEventGrp >> 8u) & 0xFFu] + 8u;
	    }
	    ptbl = &pevent->OSEventTbl[y];
	    if ((*ptbl & 0xFFu) != 0u) {
	        x = OSUnMapTbl[*ptbl & 0xFFu];
	    } else {
	        x = OSUnMapTbl[(OS_PRIO)(*ptbl >> 8u) & 0xFFu] + 8u;
	    }
	    prio = (INT8U)((y << 4u) + x);                      /* Find priority of task getting the msg       */
	#endif

	    ptcb                  =  OSTCBPrioTbl[prio];        /* Point to 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值