📌往期推文全新看点(文中附带最新·鸿蒙全栈学习笔记)
①📖 鸿蒙应用开发与鸿蒙系统开发哪个更有前景?
②📖嵌入式开发适不适合做鸿蒙南向开发?看完这篇你就了解了~
③📖 对于大前端开发来说,转鸿蒙开发究竟是福还是祸?
④📖 鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?
⑤📖 记录一场鸿蒙开发岗位面试经历~
⑥📖 持续更新中……
一、前言
本文相关代码实现位于distributedschedule_samgr_lite\communication\broadcast\source\
目录下的broadcast_service.c
和pub_sub_feature.c
。 本文将对以下数据结构及函数进行详解。
struct BroadcastService:
struct ConsumerNode:
struct Relation:
struct PubSubFeature:
在broadcast_service.c中
Init:注册广播服务
GetName:获取广播服务的名称
Initialize:广播服务的初始化函数
MessageHandle:广播服务的消息处理函数
GetTaskConfig:获取广播服务的任务配置
在pub_sub_feature.c中
Init:初始化全局广播变量
GetName:获取功能名称
OnInitialize:初始化ID
OnStop:停止功能
OnMessage:广播子功能的消息处理函数
GetRelation:获取子功能与主题的关系
IsTopicEqual:判断两个主题是否相等
二、数据结构分析
广播服务的数据结构
//广播服务消息类型
enum BroadcastMsgType {
BROADCAST_MSG, //消息类型
};
typedef struct BroadcastService BroadcastService;
//广播服务
struct BroadcastService {
INHERIT_SERVICE; //继承服务基类
};
//全局广播服务
static BroadcastService g_broadcastService = {
GetName,
Initialize,
MessageHandle,
GetTaskConfig,
};
广播服务子功能
//消费者结点
typedef struct ConsumerNode {
UTILS_DL_LIST node; //双向链表,包含prev和next指针
Consumer *consumer; //消费者
} ConsumerNode;
//关系,topic和消费者,一个topic对应多个消费者,消费者存储在双向链表中
typedef struct Relation {
UTILS_DL_LIST node; //双向链表,包含prev和next指针
ConsumerNode callbacks; //消费者结点集合,为一个双向循环链表
Topic topic; //消息标识
} Relation;
typedef struct PubSubFeature PubSubFeature;
//一个id对应一个关系双向链表,关系中又包含了一个topic和一个消费者双向链表
//一个PubSubFeature结点可以由identity标识,包含一系列关系组合
//一个relation结点可以由topic标识,包含一组消费者集合
struct PubSubFeature {
INHERIT_FEATURE; //继承功能基类
//函数指针,用于获取指定功能下的topic和消费者的关系
Relation *(*GetRelation)(PubSubFeature *feature, const Topic *topic);
MutexId mutex; //锁
Relation relations; //关系,双向循环链表
Identity identity; //身份标识,标识服务ID、功能ID和消息队列ID
};
三、函数实现详解
广播服务的函数
注册广播服务
//注册广播服务
static void Init(void)
{
SAMGR_GetInstance()->RegisterService((Service *)&g_broadcastService);
}
SYS_SERVICE_INIT(Init);
获取服务名称
//获取广播服务的名称
static const char *GetName(Service *service)
{
(void)service;
return BROADCAST_SERVICE;
}
初始化广播服务
//广播服务的初始化函数,当前代码版本暂未实现
static BOOL Initialize(Service *service, Identity identity)
{
(void)identity;
if (service == NULL) {
return FALSE;
}
return TRUE;
}
广播服务的处理函数
//广播服务的消息处理函数,当前代码版本暂未实现
static BOOL MessageHandle(Service *service, Request *request)
{
(void)service;
switch (request->msgId) {
case BROADCAST_MSG:
break;
default:
break;
}
return TRUE;
}
获取广播服务的任务配置
//获取广播服务的任务配置
static TaskConfig GetTaskConfig(Service *service)
{
(void)service;
//默认配置
TaskConfig config = {LEVEL_HIGH, PRI_ABOVE_NORMAL, 0x800, 40, SPECIFIED_TASK};
return config;
}
广播功能的函数
初始化广播功能
//初始化g_broadcastFeature,并注册feature和feature的接口
static void Init(void)
{
//获取全局广播服务子功能
PubSubFeature *feature = &g_broadcastFeature;
//初始化关系链表的头结点
feature->relations.topic = -1;
feature->relations.callbacks.consumer = NULL;
//初始化关系的双向链表,让prev和next都指向自身
UtilsListInit(&feature->relations.callbacks.node);
UtilsListInit(&feature->relations.node);
//申请锁
feature->mutex = MUTEX_InitValue();
//将feature注册到服务BROADCAST_SERVICE中
SAMGR_GetInstance()->RegisterFeature(BROADCAST_SERVICE, (Feature *)feature);
//通过feature创建一个PubSubImplement实例
PubSubImplement *apiEntry = BCE_CreateInstance((Feature *)feature);
//为feature注册接口
SAMGR_GetInstance()->RegisterFeatureApi(BROADCAST_SERVICE, PUB_SUB_FEATURE, GET_IUNKNOWN(*apiEntry));
}
SYS_FEATURE_INIT(Init);
获取功能名称
//初始化g_broadcastFeature,并注册feature和feature的接口
static void Init(void)
{
//获取全局广播服务子功能
PubSubFeature *feature = &g_broadcastFeature;
//初始化关系链表的头结点
feature->relations.topic = -1;
feature->relations.callbacks.consumer = NULL;
//初始化关系的双向链表,让prev和next都指向自身
UtilsListInit(&feature->relations.callbacks.node);
UtilsListInit(&feature->relations.node);
//申请锁
feature->mutex = MUTEX_InitValue();
//将feature注册到服务BROADCAST_SERVICE中
SAMGR_GetInstance()->RegisterFeature(BROADCAST_SERVICE, (Feature *)feature);
//通过feature创建一个PubSubImplement实例
PubSubImplement *apiEntry = BCE_CreateInstance((Feature *)feature);
//为feature注册接口
SAMGR_GetInstance()->RegisterFeatureApi(BROADCAST_SERVICE, PUB_SUB_FEATURE, GET_IUNKNOWN(*apiEntry));
}
SYS_FEATURE_INIT(Init);
初始化身份标识
//为feature配置身份标识
static void OnInitialize(Feature *feature, Service *parent, Identity identity)
{
(void)parent;
((PubSubFeature *)feature)->identity = identity;
}
停止广播功能
//停止指定的功能
static void OnStop(Feature *feature, Identity identity)
{
(void)feature;
(void)identity;
}
广播功能的消息处理
/*
函数功能:广播功能的消息处理函数
函数参数:@feature:功能对象
@request:请求消息
函数返回:处理成功 返回TRUE,处理失败 返回FALSE
函数描述:根据请求消息的消息类型执行不同的处理逻辑。这里只实现了MSG_PUBLISH类型的消息的处理方法。
*/
static BOOL OnMessage(Feature *feature, Request *request)
{
//获取广播功能对象
PubSubFeature *broadcast = (PubSubFeature *)feature;
switch (request->msgId) {//获取消息ID
case MSG_PUBLISH: {//消息类型为发布
//获取消息值,存储的是topic值,使用msgValue一般传输的是小消息,更快和便携。而使用data传输大消息
Topic topic = request->msgValue;
//获取广播功能与topic的关系
Relation *relation = broadcast->GetRelation(broadcast, &topic);
if (relation == NULL) {
//无关系,则返回false
return FALSE;
}//找到关系
//加锁
MUTEX_Lock(broadcast->mutex);
ConsumerNode *item = NULL;
/*
UTILS_DL_LIST_FOR_EACH_ENTRY(item, list, type, member)用于迭代给定类型的双链表
UTILS_DL_LIST_ENTRY(item, type, member)用于获取指向包含双链表的结构的指针
*/
//遍历指定关系下的消费者集合的双向链表,遍历topic下的每一个消费者的信息
UTILS_DL_LIST_FOR_EACH_ENTRY(item, &relation->callbacks.node, ConsumerNode, node) {
//消费者的身份ID为NULL
if (item->consumer->identity == NULL) {
//消费者处理已发布的topic中的事件或数据
item->consumer->Notify(item->consumer, &topic, request);
}
}
MUTEX_Unlock(broadcast->mutex);
}
break;
default:
break;
}
return TRUE;
}
获取广播功能中特定topic的关系
//获取给定的topic在feature中的关系
static Relation *GetRelation(PubSubFeature *feature, const Topic *topic)
{
//参数检查
if (feature == NULL || topic == NULL) {
return NULL;
}
//获取指定功能的关系集合头结点,这是一个双向链表
UTILS_DL_LIST *list = &feature->relations.node;
Relation *item = NULL;
MUTEX_Lock(feature->mutex);
//遍历关系集合的链表,获取每一个关系的信息
UTILS_DL_LIST_FOR_EACH_ENTRY(item, list, Relation, node) {
if (IsTopicEqual(&item->topic, topic)) {//判断两个topic的值是否相等
//topic匹配成功,返回对应的relation
MUTEX_Unlock(feature->mutex);
return item;
}
}
MUTEX_Unlock(feature->mutex);
return NULL;
}
判断topic是否相同
//判断两个topic的值是否相等
static BOOL IsTopicEqual(const Topic *current, const Topic *other)
{
return *current == *other;
}