OpenHarmony轻量系统服务管理-IUnknown

前言

  iunknown是针对服务和功能的统一对外接口,头文件位于distributedschedule_samgr_lite\interfaces\kits\samgr\iunknown.hiunknown为系统功能的外部功能提供基类和默认实现。

IUnknown背景

  要想清楚的理解IUnknown就必须知道COM标准到底是什么。

  COM全称Component Object Model,即组件对象模型,这是一种遵循COM规范的面向对象编程技术。它包含了三个基本的接口类,分别是IUnknownIClassFactoryIDispatch。除了IUnknown以外,在鸿蒙后续的代码中,我们也会看到IClassFactoryIDispatch的身影,这里先分析IUnknown。COM规定任何的组件或接口都必须从IUnknown继承,而我在对模块二后续代码的分析中发现了大量的案例,如PubSubInterfaceIClientProxyIServerProxy等。IUnknown包含三个函数,分别是QueryInterfaceAddRefRelease

  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 }
复制代码

 

posted @   沉心慢慢  阅读(275)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示