ucos信号量集源码分析
在实际的应用之中,一个任务经常需要等待多个信号量的同时生效,或者说任务需要根据多个信号量的组合作用的结果来决定任务的运行方式,为了实现这种多信号量组合的功能,ucos实现了信号量集的特殊结构.
信号量集的基础仍然是信号量,它如同一个多个信号量组成的与非门来构成逻辑结果控制任务的执行.
信号量在ucos的实现分为两个部分,第一部分叫做标志组,其中存放了信号量集中的所有信号,第二个叫做等待任务链表,链表中的每个节点对应一个正在等待信号量集的等待任务,信号量集根据这个链表来管理等待任务
不同于消息队列消息邮箱等事件,ucos定义信号量集的时候使用了一种新的结构叫做标志组,其结构如下
typedef struct os_flag_grp { /* 事件标志组*/
INT8U OSFlagType; /* 信号量集标志,必须为OS_EVENT_TYPE_FLAG */
void *OSFlagWaitList; /* 指向任务等待组第一个节点的指针 */
OS_FLAGS OSFlagFlags; /*信号量集的长度*/
#if OS_FLAG_NAME_EN > 0u
INT8U *OSFlagName;
#endif
} OS_FLAG_GRP;
前几个都有注释,注意OSFlagFlags,这是一个OS_FLAGS类型的变量,在OSFlagFlags中,一个位代表一个信号量,一个标志组能容纳多少信号量取决于OS_FLAGS的长度,而OS_FLAGS的长度定义可以使8位 16位 32位的,如下
#if OS_FLAGS_NBITS == 8u
typedef INT8U OS_FLAGS;
#endif
#if OS_FLAGS_NBITS == 16u
typedef INT16U OS_FLAGS;
#endif
#if OS_FLAGS_NBITS == 32u
typedef INT32U OS_FLAGS;
#endif
决定其长度的宏在os_cfg.h文件中指定,一般指定为16位,根据需要决定
OSFlagWaitList指向的是等待这个信号量集的任务链表的指针,一个信号量集创建之后并没有直接和任务连接上,这点之后再说,我们先看看系统如何管理信号量集
其实信号量集的管理和之前tcb ecb以及qcb的管理类似,都是空闲链表的形式,在系统中有着一个标志组数组,如下
OS_EXT OS_FLAG_GRP OSFlagTbl[OS_MAX_FLAGS];
该变量指明系统最多包含的标志组的大小, OS_MAX_FLAGS是在os_cfg.h文件中定义的宏,用户根据需要进行配置
在标志组初始化的时候可以看到如下代码
for (ix = 0u; ix < (OS_MAX_FLAGS - 1u); ix++) { /* Init. list of free EVENT FLAGS */
ix_next = ix + 1u;
pgrp1 = &OSFlagTbl[ix];
pgrp2 = &OSFlagTbl[ix_next];
pgrp1->OSFlagType = OS_EVENT_TYPE_UNUSED;
pgrp1->OSFlagWaitList = (void *)pgrp2;
#if OS_FLAG_NAME_EN > 0u
pgrp1->OSFlagName = (INT8U *)(void *)"?"; /* Unknown name */
#endif
}
pgrp1 = &OSFlagTbl[ix];
pgrp1->OSFlagType = OS_EVENT_TYPE_UNUSED;
pgrp1->OSFlagWaitList = (void *)0;
#if OS_FLAG_NAME_EN > 0u
pgrp1->OSFlagName = (INT8U *)(void *)"?"; /* Unknown name */
#endif
OSFlagFreeList = &OSFlagTbl[0];
可以很明显的看出来,信号量集的管理类似于tcbqcb等,都是使用链表的方式管理的,在初始化的时候用一个OSFlagFreeList指向一个标志组作为空闲标志组的表头, OSFlagWaitList在没有创建标志组的时候作为链表连接各个标志组变量
OSFlagWaitList的定义如下
OS_EXT OS_FLAG_GRP *OSFlagFreeList;
这是标志组的组织,那么如何让标志组与信号量集产生关联,依靠的函数为OS_FlagBlock,原型如下
static void OS_FlagBlock (OS_FLAG_GRP *pgrp,
OS_FLAG_NODE *pnode,
OS_FLAGS flags,
INT8U wait_type,
INT32U timeout)
第一个参数是我们生成的标志组,第二个为一个pnode变量, flags为指定等待的信号量集数据,第四个为等待类型,最后为等待超时事件
挑简单的先说,等待时间不用赘述,前面已经仔细分析过,说说等待类型,标志组的等待类型分为八种,分别如下
#define OS_FLAG_WAIT_CLR_ALL 0u //信号全部有效才能继续执行任务
#define OS_FLAG_WAIT_CLR_AND 0u //但是信号有效的标识是0有效
#define OS_FLAG_WAIT_CLR_ANY 1u //信号有一个或者一个以上有效
#define OS_FLAG_WAIT_CLR_OR 1u //但是信号有效的标识是0有效
#define OS_FLAG_WAIT_SET_ALL 2u //信号全部有效才能继续执行任务
#define OS_FLAG_WAIT_SET_AND 2u //信号有效的标识是1有效
#define OS_FLAG_WAIT_SET_ANY 3u //信号有一个或者一个以上有效
#define OS_FLAG_WAIT_SET_OR 3u //信号有效的标识是1有效
举个例子,如果此时OSFlagFlags为0b00000000,此时设置为OS_FLAG_WAIT_CLR_ALL的任务就有效,而设置为OS_FLAG_WAIT_SET_ALL的信号是无效的,因为信号位为0的时候有效,全部为0,所以有效, 信号位为1的时候有效,没有一个位是1,所以无效.
还有一个OS_FLAG_NODE元素,该元素的定义如下
typedef struct os_flag_node {
void *OSFlagNodeNext; /*指向下一个node节点 */
void *OSFlagNodePrev; /* 指向上一个node节点*/
void *OSFlagNodeTCB; /*指向当前任务节点的tcb*/
void *OSFlagNodeFlagGrp;
OS_FLAGS OSFlagNodeFlags;
INT8U OSFlagNodeWaitType; /* 当前等待类型 */
} OS_FLAG_NODE;
成员OSFlagNodeFlagGrp是一个反向指向信号量集标志组的指针,在等待任务链表中删除一个成员的时候或者添加成员的时候需要用到
OSFlagNodeFlags相当于一个过滤器,能够从标志组中将请求任务所需的信号量筛选出来,其余的无关信号屏蔽掉,
建立节点与标志组连接关系的接口为OS_FlagBlock,核心代码如下
OSTCBCur->OSTCBStat |= OS_STAT_FLAG;
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
OSTCBCur->OSTCBDly = timeout; /* Store timeout in task's TCB */
#if OS_TASK_DEL_EN > 0u
OSTCBCur->OSTCBFlagNode = pnode; /* TCB to link to node */
#endif
pnode->OSFlagNodeFlags = flags; /* Save the flags that we need to wait for */
pnode->OSFlagNodeWaitType = wait_type; /* Save the type of wait we are doing */
pnode->OSFlagNodeTCB = (void *)OSTCBCur; /* Link to task's TCB */
pnode->OSFlagNodeNext = pgrp->OSFlagWaitList; /* Add node at beginning of event flag wait list */
pnode->OSFlagNodePrev = (void *)0;
pnode->OSFlagNodeFlagGrp = (void *)pgrp; /* Link to Event Flag Group */
pnode_next = (OS_FLAG_NODE *)pgrp->OSFlagWaitList;
if (pnode_next != (void *)0) { /* Is this the first NODE to insert? */
pnode_next->OSFlagNodePrev = pnode; /* No, link in doubly linked list */
}
pgrp->OSFlagWaitList = (void *)pnode;
y = OSTCBCur->OSTCBY; /* Suspend current task until flag(s) received */
OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;
if (OSRdyTbl[y] == 0x00u) {
OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
可以看到,他会先将任务挂起,然后
pnode->OSFlagNodeNext = pgrp->OSFlagWaitList;
将任务放入等待任务列表中,最后将等待任务列表的头切换成我们刚才插入的节点,如下
pgrp->OSFlagWaitList = (void *)pnode;
这样,任务就和信号量集联系在了一起,在调度的时候我们可以说应该是在postxxx里面调度的,查看之后发现如下代码
sched = OS_FALSE; /* Indicate that we don't need rescheduling */
pnode = (OS_FLAG_NODE *)pgrp->OSFlagWaitList;
while (pnode != (OS_FLAG_NODE *)0) {
.........
pnode = (OS_FLAG_NODE *)pnode->OSFlagNodeNext;
}
if (sched == OS_TRUE) {
OS_Sched();
}
也就是说,在别的任务发送信号量集的时候,该信号量集内部会发生一次等待列表的遍历操作,选择出合适的可以调度的任务,然后调用OS_Sched进行调度,从而实现信号量集
说到这里,基本上信号量集的原理上的东西就差不多了,现在说说使用
创建信号量集
OSFlagCreate,返回创建的信号量集的指针
请求信号量集
OSFlagPend
向信号量集发送信号
OSFlagPost
查询信号量集的状态
OSFlagQuery
删除信号量集
OSFlagDel
向信号量集中添加任务(这个很重要)
OS_FlagBlock,这个函数有一个OS_FLAG_NODE的参数,在生成这个变量的时候,只需要赋值waittype和flags两个,其余的接口会自动赋值,不需要用户也不能去手动赋值,切记
ucos信号量集源码分析的更多相关文章
- Semaphore(信号量)源码分析
1. Semaphore Semaphore和ReentrantReadWriteLock.ReadLock(读锁)都采用AbstractOwnableSynchronizer共享排队的方式实现. 关 ...
- quartz集群调度机制调研及源码分析---转载
quartz2.2.1集群调度机制调研及源码分析引言quartz集群架构调度器实例化调度过程触发器的获取触发trigger:Job执行过程:总结:附: 引言 quratz是目前最为成熟,使用最广泛的j ...
- (1)quartz集群调度机制调研及源码分析---转载
quartz2.2.1集群调度机制调研及源码分析 原文地址:http://demo.netfoucs.com/gklifg/article/details/27090179 引言quartz集群架构调 ...
- [转]RMI方式Ehcache集群的源码分析
RMI方式Ehcache集群的源码分析 Ehcache不仅支持基本的内存缓存,还支持多种方式将本地内存中的缓存同步到其他使用Ehcache的服务器中,形成集群.如下图所示: Ehcache支持 ...
- RMI方式Ehcache集群的源码分析
Ehcache不仅支持基本的内存缓存,还支持多种方式将本地内存中的缓存同步到其他使用Ehcache的服务器中,形成集群.如下图所示: Ehcache支持多种集群方式,下面以RMI通信方式为例,来具体分 ...
- 分布式缓存技术之Redis_Redis集群连接及底层源码分析
目录 1. Jedis 单点连接 2. Jedis 基于sentinel连接 基本使用 源码分析 本次源码分析基于: jedis-3.0.1 1. Jedis 单点连接 当是单点服务时,Java ...
- Dubbo 源码分析 - 集群容错之 LoadBalance
1.简介 LoadBalance 中文意思为负载均衡,它的职责是将网络请求,或者其他形式的负载"均摊"到不同的机器上.避免集群中部分服务器压力过大,而另一些服务器比较空闲的情况.通 ...
- Dubbo 源码分析 - 集群容错之 Cluster
1.简介 为了避免单点故障,现在的应用至少会部署在两台服务器上.对于一些负载比较高的服务,会部署更多台服务器.这样,同一环境下的服务提供者数量会大于1.对于服务消费者来说,同一环境下出现了多个服务提供 ...
- Dubbo 源码分析 - 集群容错之 Router
1. 简介 上一篇文章分析了集群容错的第一部分 -- 服务目录 Directory.服务目录在刷新 Invoker 列表的过程中,会通过 Router 进行服务路由.上一篇文章关于服务路由相关逻辑没有 ...
随机推荐
- Moya 浅析
Moya是一个高度抽象的网络库,他的理念是让你不用关心网络请求的底层的实现细节,只用定义你关心的业务.且Moya采用桥接和组合来进行封装(默认桥接了Alamofire),使得Moya非常好扩展,让你不 ...
- HBase性能优化方法总结(一):表的设计
本文主要是从HBase应用程序设计与开发的角度,总结几种常用的性能优化方法.有关HBase系统配置级别的优化,可参考:淘宝Ken Wu同学的博客. 下面是本文总结的第一部分内容:表的设计相关的优化方法 ...
- [原]左右的移动<<>><>jQuery的实现
$(function () { $('#toAllLeft').click(function () { $('#se1 option').app ...
- L9,a cold welcome
expression: a large crowd of 一大群 in twenty minutes’time 20分钟之后 一些时间使用的介词 in two year‘s time on Satur ...
- AJAX(XMLHttpRequest)进行跨域请求方法详解(一)
注意:以下代码请在Firefox 3.5.Chrome 3.0.Safari 4之后的版本中进行测试.IE8的实现方法与其他浏览不同. 跨域请求,顾名思义,就是一个站点中的资源去访问另外一个不同域名站 ...
- 迄今最安全的MySQL?细数5.7那些惊艳与鸡肋的新特性(上)【转载】
转自: DBAplus社群 http://www.toutiao.com/m5762164771/ 迄今最安全的MySQL?细数5.7那些惊艳与鸡肋的新特性(上) - 今日头条(TouTiao.com ...
- Android Studio中有没有类似于Eclipse中的ctrl+2+L的快捷键? \Android Studio快捷键之代码提示
问:Android Studio中有没有类似于Eclipse中的ctrl+2+L的快捷键? 答:有,as中的快捷键是Ctrl+Alt+V AndroidStudio和Eclipse常用快捷键对比 功能 ...
- 格式化一个文件的大小(size),或者说是格式化一个app的大小(size)
long number = 6243161; Formatter.formatFileSize(context, number): 需要导包,import android.text.format.Fo ...
- 转 如何高效使用和管理Bitmap--图片缓存管理模块的设计与实现
上周为360全景项目引入了图片缓存模块.因为是在Android4.0平台以上运作,出于惯性,都会在设计之前查阅相关资料,尽量避免拿一些以前2.3平台积累的经验来进行类比处理.开发文档中有一个 Bitm ...
- apache RewriteCond RewriteRule
http://www.rockbb.com/blog/?p=319 http://www.cnblogs.com/scgw/archive/2011/12/10/2283029.html 我的理解:当 ...