uCOS学习笔记(四)——事件标志组

6、关于事件标志组

一、用来保存当前事件组中各事件状态的一些标志位;二、等待这些标志位置位或清除的任务列表

事件标志组和事件标志节点用于挂接每个等待事件的任务,假设当前任务等待的事件标志没能就绪,那么当前任务需要被挂起等待,通过当前任务调用OS_FlagBlock()实现,首先需要添加当前任务到事件标志组等待任务链表中(采用前向挂接,即下一个节点挂接在上一个前向),然后清除该任务就绪标志,具体实现如下:

static  void  OS_FlagBlock (OS_FLAG_GRP *pgrp, OS_FLAG_NODE *pnode, OS_FLAGS flags, INT8U wait_type, INT16U timeout)
{
    OS_FLAG_NODE  *pnode_next;

    OSTCBCur->OSTCBStat      |= OS_STAT_FLAG;         /*OS_FlagBlock()首先设置任务控制块的相应变量。注意到OS_FLAG_NODE数据结构是存放在调用OSFlagePend()的任务堆栈中的。这就不需要维持一个全局的空闲OS_FLAG_NODE链表,因为可以很方便的在任务堆栈中得到这样大的数据结构空间。这同时也意味着,任务堆栈必须有足够的空间,以保证可以存放OS_FLAG_NODE数据结构。*/
    OSTCBCur->OSTCBDly        = timeout;              /* Store timeout in task's TCB*/
#if OS_TASK_DEL_EN > 0
    OSTCBCur->OSTCBFlagNode   = pnode;                /* 初始化OSTCBFlagNode指针(这个指针是OS_FLAG_NODE类型的),使其指向当前OS_FLAG_NODE节点,相当于将当其节点数据结构保存在任务控制块的一个链接中,前提是常量OS_TASK_DEL_EN必须被置为1。这样在调用OSTaskDel()时,可以根据这个连接把要删除的任务从对应的事件标志组的等待任务列表中删除。当然,这个删除操作是由其他的任务完成的。*/
#endif
    pnode->OSFlagNodeFlags    = flags;                /* OS_FlagBlock()保存任务等待事件标志组的指定事件标志位和等待等待方式的信息。*/
    pnode->OSFlagNodeWaitType = wait_type;            /* Save the type of wait we are doing*/
    pnode->OSFlagNodeTCB      = (void *)OSTCBCur;   /* 把任务控制块指针保存到OS_FLAG_NODE的任务控制块链接中,这样可以直接在节点中找到当前任务控制块。*/
    pnode->OSFlagNodeNext     = pgrp->OSFlagWaitList; /*由于OSFlagWaitList指针始终指向最前的那个节点,对于新添加节点而言,即为指向后一个节点的指针*/
    pnode->OSFlagNodePrev     = (void *)0;            /*新增加的OS_FLAG_NODE节点已经是双向链表的开始端,因而指向上一个节点的指针为0。*/
    pnode->OSFlagNodeFlagGrp  = (void *)pgrp;         /* 事件标志组的指针被反向链接到OS_FLAG_NODE的事件标志组指针中。当删除一个任务时,需要根据这个链表把被删除的任务从对应的事件标志组的等待任务列表中删除。*/
    pnode_next                = (OS_FLAG_NODE *)pgrp->OSFlagWaitList;
    if (pnode_next != (void *)0) {                    /*pnode_next后一个节点,也就是OSFlagWaitList指向的最前的节点,如果后一个节点存在,那么让后一个节点的OSFlagNodePrev指向前一个节点,也就是当前节点,完成双向链表构造 */
        pnode_next->OSFlagNodePrev = pnode; 
    }
    pgrp->OSFlagWaitList = (void *)pnode;			/* 等待任务列表的起始指针,被更新为新添加的OS_FLAG_NODE节点指针,使得OSFlagWaitList指向最前的节点。*/
    if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {
        OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
    }
}/*将任务从就绪任务列表中删除,完成任务的挂起*/


下面转自一位网友的博客

比如,我现在用迅雷下载一部10集的连续剧,我打算10集全部下载完成之后,才开始正式看,现在3~10集因为种子原因,先早下完了,现在第1集下到了82%,第2集下到了97%,因为我的计划是10集全部下完才开始看,而第1集和第2集由于网络、种子等等各种原因,迟迟不能下载完成,进而导致我的计划被悬停,不能进行,已下载的8集,也因为前2集没能下完,而白白等待---这就等同于flag事件组。

1~10集,每一集都是一个事件,因为我内定,10个事件全部完成之后,才进入下一事件--"观看",所以及早完成自己事件的第3~10集,将主动把自己通过flag事件组函数OSFlagPost()登记到事件组上,他们不关心,其他友邻事件完成否,只专注自己的事件是否完成,自己的事件一旦完成就登记到事件组上,最后3~10集,都把自己登记上去了,只剩下第1集和第2集,一旦某天的某个时刻,第2集下完了,那么第2集也把自己登记到事件组上,这样整个事件距离完成还剩下一个事件,就是第1集是否下载完成,只要第1集下载完成,那么我内定的“观看计划”开始启动,过了3分钟,由于网速提高,竟以300k的速度开始下载第1集,1分钟之后,第1集也下载完成了,第1集立即调用OSFlagPost事件组函数,将自己登记到事件组上,ok,OSFlagPost()检测到所有事件已经完成,OSFlagPost()将是"我"自动进入下一事件---"观看",还有一点就是关于flag事件组和Sem、Mbox、Queue的区别之处,flag事件组不使用事件控制矩阵来管理被阻塞在事件上的task进程,flag事件组使用pgrp的双向链表来挂接起所有task,

在OSFlagPost()中将遍历这个链表,查找符合当前flag事件的task,将该task从双向链表中摘下然后放入就绪控制矩阵中,之所以这样,是因为flag事件组不像Sem、Mbox、Queue那样具有二值性,即Sem、Mbox、Queue,要么有、要么没有,flag事件组,还要进一步判断,有的话,是什么程度的有。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值