OpenHarmony轻量系统服务管理-IUnknown
前言
iunknown是针对服务和功能的统一对外接口,头文件位于distributedschedule_samgr_lite\interfaces\kits\samgr\iunknown.h
。iunknown
为系统功能的外部功能提供基类和默认实现。
IUnknown背景
要想清楚的理解IUnknown
就必须知道COM标准到底是什么。
COM全称Component Object Model
,即组件对象模型,这是一种遵循COM规范的面向对象编程技术。它包含了三个基本的接口类,分别是IUnknown
、IClassFactory
和IDispatch
。除了IUnknown
以外,在鸿蒙后续的代码中,我们也会看到IClassFactory
和IDispatch
的身影,这里先分析IUnknown
。COM规定任何的组件或接口都必须从IUnknown
继承,而我在对模块二后续代码的分析中发现了大量的案例,如PubSubInterface
、IClientProxy
、IServerProxy
等。IUnknown
包含三个函数,分别是QueryInterface
、AddRef
、Release
。
QueryInterface
:查询实现的接口类,需要注意查询完后要调用release解除引用
AddRef
:增加引用计数
Release
:减少引用计数
看到这里可能会很疑惑,引用计数是什么,有什么作用?我们为什么要使用引用计数?
引用计数牵涉到内存管理的概念,每增加1就代表当前组件被一个对象引用,每减少1就代表当前组件少一个引用者,当引用计数为0时,就代表已经没有对象使用它了,那么它的生命周期就到此结束,释放自己占用的资源。通过引用计数来管理自己的生命周期,不需要其他对象的干预,这种方式极大的减少了代码开发者的工作。这种方式就跟C++11中的智能指针一样,通过引用计数来控制对象的生命周期,减少开发者的工作,避免内存泄漏。
结构体分析
1 //结构体的声明,包含QueryInterface函数指针、AddRef函数指针、Release函数指针 2 struct IUnknown { 3 //查询指定版本接口的子类对象 4 int (*QueryInterface)(IUnknown *iUnknown, int version, void **target); 5 //添加引用计数 6 int (*AddRef)(IUnknown *iUnknown); 7 //释放对接口的引用 8 int (*Release)(IUnknown *iUnknown); 9 }; 10 typedef struct IUnknownEntry { 11 //接口版本信息 12 uint16 ver; 13 //接口的引用计数。 14 int16 ref; 15 //IUnknown接口成员 16 IUnknown iUnknown; 17 } IUnknownEntry;
宏定义分析
1 //定义用于继承IUnknown接口的宏 2 //当开发IUnknown类的子类时,可以使用这个宏来继承IUnknown接口结构 3 #define INHERIT_IUNKNOWN \ 4 int (*QueryInterface)(IUnknown *iUnknown, int version, void **target); \ 5 int (*AddRef)(IUnknown *iUnknown); \ 6 int (*Release)(IUnknown *iUnknown) 7 //定义用于继承实现IUnknown接口的类的宏 8 //当开发一个实现了IUnknown接口的类的子类时,可以使用这个宏继承IUnknown实现类的结构 9 #define INHERIT_IUNKNOWNENTRY(T) \ 10 uint16 ver; \ 11 int16 ref; \ 12 T iUnknown 13 //定义初始化IUnknown接口的默认宏 14 //当创建IUnknown接口的子类对象时,可以使用此宏将IUnknown接口的成员初始化为默认值 15 #define DEFAULT_IUNKNOWN_IMPL \ 16 .QueryInterface = IUNKNOWN_QueryInterface, \ 17 .AddRef = IUNKNOWN_AddRef, \ 18 .Release = IUNKNOWN_Release 19 //定义用于初始化实现IUnknown接口的类的宏。 20 //当创建实现IUnknown接口的类的子类对象时,可以使用这个宏将IUnknown实现类的成员初始化为默认值 21 #define IUNKNOWN_ENTRY_BEGIN(version) \ 22 .ver = (version), \ 23 .ref = 1, \ 24 .iUnknown = { \ 25 DEFAULT_IUNKNOWN_IMPL
主要函数分析
为IUnknown对象添加引用
1 //增加iUnknown接口的引用计数,当重新实现QueryInterface函数时,需要在新的QueryInterface中调用该函数 2 int IUNKNOWN_AddRef(IUnknown *iUnknown) 3 { 4 if (iUnknown == NULL) { 5 return EC_INVALID; 6 } 7 //返回IUnknownEntry类型的地址,通过iUnknown的地址推断 8 IUnknownEntry *entry = GET_OBJECT(iUnknown, IUnknownEntry, iUnknown); 9 entry->ref++;//引用计数加1 10 return entry->ref; 11 }
查询接口信息
1 /* 2 函数功能:查询接口信息 3 函数参数:@iUnknown:iUnknown对象 4 @ver:版本号 5 @target:返回需要的IUnknown的子类类型 6 函数返回:成功 返回EC_SUCCESS,失败 返回EC_INVALID 7 函数描述: 8 1.查询指定版本的IUnknown接口。 9 2.在获得IUnknown接口对象后,函数调用者使用QueryInterface将该对象转换为所需的子类类型,内部将转换为调用者所需的子类类型。 10 */ 11 int IUNKNOWN_QueryInterface(IUnknown *iUnknown, int ver, void **target) 12 { 13 //参数检查 14 if (iUnknown == NULL || target == NULL) { 15 return EC_INVALID; 16 } 17 //返回IUnknownEntry类型的地址,通过iUnknown的地址推断 18 IUnknownEntry *entry = GET_OBJECT(iUnknown, IUnknownEntry, iUnknown); 19 //判断版本信息是否有效 20 if ((entry->ver & (uint16)ver) != ver) { 21 return EC_INVALID; 22 } 23 if (ver == OLD_VERSION && 24 entry->ver != OLD_VERSION && 25 (entry->ver & (uint16)DEFAULT_VERSION) != DEFAULT_VERSION) { 26 return EC_INVALID; 27 } 28 //作为返回值 29 *target = iUnknown; 30 //添加引用 31 iUnknown->AddRef(iUnknown); 32 return EC_SUCCESS; 33 }
释放引用数
1 /* 2 函数功能:释放iUnknown对象的引用数 3 函数参数:@iUnknown:iUnknown对象 4 函数返回:成功 引用计数,失败 返回EC_INVALID 5 详细描述: 6 1.释放不再使用的IUnknown接口的引用 7 2.在系统提供的默认实现中,如果引用计数为0,则IUnknown接口对象和实现对象的内存不会被释放 8 */ 9 int IUNKNOWN_Release(IUnknown *iUnknown) 10 { 11 //参数检查 12 if (iUnknown == NULL) { 13 return EC_INVALID; 14 } 15 //转换为IUnknownEntry对象 16 IUnknownEntry *entry = GET_OBJECT(iUnknown, IUnknownEntry, iUnknown); 17 int ref = entry->ref - 1;//引用数-1 18 if (ref < 0) { 19 //存在异常 20 } else { 21 if (ref == 0) { 22 //iunknown对象的引用数为0,应删除 23 //在默认版本中,iunknown可能是全局变量,默认不删除。 24 } else { 25 entry->ref = ref;//更新计数 26 } 27 } 28 return ref; 29 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了