信号量集的本质还是信号量,有多个信号量来决定一个任务时候进行
1.为什么要引入信号量集?
信号量(特别是二值信号量)实质上就是一种条件标志,任务请求信号量的操作等同于下面语句
if(信号量值>0)
进行下面操作
else
等待
即,信号量代表了程序继续运行时所需要的前提条件,只不过这个条件满足与否通常取决于其他任务的行为。正像我们要买衣服一样,买衣服的操作能否完成,取决于老板是否把工资付给了你。其实,再深入思考一下就会知道,是否实施买衣服的操作,除了需要钱以外,还取决于服装商店是否正在营业。
if(钱 > 0 && 商店 == open)
买衣服
else
等待
也就是说,在程序中一个任务的操作是否实施,常常需要由多个信号量的逻辑运算结果作为前提条件。为了处理此类问题,ucos提供了可以处理多个信号量的信号量集。

2。信号量集的结构
ucos把信号量集的功能分成了两部分:标志组和等待任务链表。标志组中存放了信号量集的所有信号,而等待任务链表中的每个结点都对应着一个叫做OS_FLAG_NODE的结构。OS_FLAG_NODE结构实质上就是等待任务控制块。也就是说,ucos的信号量集由一个标志组和多个等待任务控制块构成

(1)信号量集的标志组
所谓标志组,其实更应该叫做输入信号标志组,其主要部分就是一个叫做信号列表的二进制数OSFlagFlags。OSFlagFlags其实就是一个位图,其长度可在系统配置文件OS_CFG.H中来定制,系统默认长度为16位。该位图的每一位都对应一个信号量,位图的作用就是用来接受并保存其他任务所发送过来的信号量值,所以它可以看作是输入信号暂存器。

和操作系统中的其他设施一样,信号量集也应该有一个控制块,而且这个控制块应该以OSFlagFlags作为重要成员之一。
typedef struct{
INT8U OSFlagType; //识别是否为信号量集的标志
void *OSFlagWaitList; //指向等待任务链表的指针
OS_FLAGS OSFlagFlags; //输入信号量值列表
}OS_FLAG_GRP;
可以看出OS_FLAG_GRP结构定义中,除了核心成员OSFlagFlags之外,还有OSFlagType和OSFlagWaitList两个成员
OSFlagType作为信号量集标识,其固定为OS_EVENT_TYPE_FLAG;
OSFlagWaitList则是一个void类型的指针。他有两个用途:1.指向一个链表,2该链表中存放了信号量集的全部等待任务
(2)等待任务
所谓等待任务,就是那些已经向信号量集发出了请求操作的任务
等待任务需要做的操作很多
1把多个信号量的输入中挑选等待任务感兴趣的输入
2把挑选出来的输入按照等待任务所希望的逻辑进行计算,已得到输出
即



为了解决第一个问题:ucos定义了长度与输入标志列表OSFlagFlags相等的OSFlagNodeFlags,目的就是让他作为过滤器从输入列表中筛选出等待任务感兴趣的输入
为了解决第二个问题:ucos又定义了一个OSFlagNodeWaitType变量来制定对筛选出来的信号进行逻辑判断


3等待任务链表
与其他前面介绍过的事件不同,信号量集用一个双向链表来组织等待任务,每一个等待任务就是该链表中的一个节点(Node)标志组中的OS_FLAG_GRP成员OSFlagWaitList就指向了信号量集的这个等待任务链表。
对等待任务链表的操作
(1)添加节点 OS_FlagBlock()
(2)删除节点 OS_FlagUnlink()
4
空标志组链表
ucos在初始化时,系统会根据在文件OS_CFG.H中定义的常数OS_MAX_FLAGS创建OS_MAX_FLAGS个标志组,并借用成员OSFlagWaitList作为指针把这些标志组链成一个单向链表。由于这个链表中的各个标志组还未被真正创建,因此这个链表叫做空标志组链表

对信号量集的操作
1 创建信号量集 OSFlagCreate()
OS_FLAG_GRP *OSFlagCreate(
OS_FLAGS flags, //信号的初值
INT8U *err //错误信息
)
创建信号量集主要做了两项工作:1.从空标志组链表中去下一个标志组,同时给成员OSFlagType和OSFlagFlags赋初值; 2,令指向等待任务链表的指针OSFlagWaitList为空指针
这里OSFlagsFlags可以根据需要赋值
创建一个信号量集分为两个步骤:首先定义一个全局的OS_FLAG_GRP类型的指针,然后在应用程序中需要创建信号量集的位置调用函数OSFlagCreate()

函数的返回值是信号量集的标志组的指针
2
请求信号量集 OS_FLAGS OSFlagPend(
OS_FLAG_GRP *pgrp, //所请求的信号集指针
OS_FLAGS flags, //滤波器
INT8U wait_type, //逻辑运算类型
INT16U timeout , //等待时限
INT8U *err //错误信息
);
(OS_FLAGS) flag 表示等待任务对第几位(可以为多位)信号感兴趣
也可以采用OS_FLAGS OSFlagAccept(
OS_FLAG_GRP *pgrp, //所请求的信号量集指针
OS_FLAGS flags, //所请求的信号
INT8U wait_type, //任务就绪与信号之间的逻辑关系
INT8U *err //错误信息
);
来避免等待

3
向信号量集发送信号 OS_FLAGS OSFlagPost(
OS_FLAG_GRP *pgrp , //信号量集指针
OS_FLAGS flag , //选择所要发送的信号
INT8U opt, //信号有效的选项
INT8U *err //错误信息
);
所谓任务向信号集发送信号,就是对信号量集标志组中的信号进行置1或者置0.。至于对信号量集中的哪些信号进行操作,有函数中的参数flags来决定;对指定信号置1还是置0,由函数中的参数opt来决定(opt == OS_FLAG_SET 为置一操作;opt = OS_FLAG_CLR 为置0操作)
例如要对信号量集FlagPtr发送信号,待发送的信号为OSFlagFlags中的第0位和第3位,并且是要把它们置1

查询信号量集的状态 OSFlagQuery()
OS_FLAGS OSFlagQuery(
OS_FLAG_GRP *pgrp, //待查询的信号量集的指针
INT8U *err //错误信息
);
删除信号量集
OS_FLAG_GRP *OSFlagDel(
OS_FLAG_GRP *pgrp, //待删除的信号量集指针
INT8U opt,
INT8U *err //错误信息
);