进程能通信——智能指针

作者: 某昆 | 来源:发表于2018-03-31 13:51 被阅读122次

    本文主要内容

    • 进程通信概念
    • 智能指针概念
    • 强指针
    • 弱指针

    进程通信概念

    同一个程序中两个函数能互相调用的根本原因是处于相同的内存空间中

    因为是在同一个内存空间当中,虚拟地址的映射规则完全一致,所以不同函数间能找到另一函数的内存地址,所以可以调用到。

    反之不同进程间,它们是没有办法直接调用另一进程的方法或者变量的。

    Binder,粘合剂,它是android中使用最广泛的IPC机制。如果将Binder和TCP网络类比,会发现他们很相似:

    • Binder驱动器 —— 路由器
    • Service Manager ——DNS
    • Binder Client —— 客户端
    • Binder Server —— 服务器

    智能指针概念

    c/c++指针常常会有以下问题:

    • 指针没有初始化
    • new了对象后没有及时delete
    • 野指针,如果指针ptr指向对象obj,obj已经被delete了,但唯一没做的是将ptr置空,此时ptr就是野指针,如果在其它地方使用ptr,程序肯定会发生异常

    针对以上三个问题,智能指针出现了。

    第1个问题很好解决,只要在智能指针出现的时候置null即可。

    为了解决第2个问题,我们使用引用计数法,计算当前对象被引用的次数,如果引用次数大于0,则不删除,反之则删除。

    计数器由object自身管理,不能由智能指针管理,因为智能指针不能处理自己之外的引用。

    object中实现增加计数和减少计数的方法,当智能指针引用此object时候增加计数,不再引用时则减少计数。

    如上图所示,重载等号,在使用行号赋值的时候调用object的增加计数方法,在析构函数中,调用减少计数的方法。

    如果有两个智能指针同时引用一个object,就会出现下图所示:

    强指针SP

    强指针sp,是StrongPointer的缩写,来看看它的代码:

    它和前一小节的SmartPointer稍微有所不同,比如等号重载。

    如果此前 m_ptr 不为空,则说明此智能指针正在引用其它object,此时则要将之前的object减少计数。

    而其它构造函数和析构函数则与SmartPointer类似。强指针比较简单,不再赘述。

    弱指针

    引用计数法,有一个问题,就是循环引用问题,如果有两个对象互相引用,而且没有任何其它对象引用二者,那么这两对对象的计数器不为0,则永远不会被删除。

    弱指针的主要使命就是解决循环引用问题,另外弱指针只有升级为强指针,才能访问它所指向的目标。


    和sp相比,wp在定义上有以下区别:

    • 除了指向目标的m_ptr之外,wp另外还有一个m-refs指针,类型为 weakref_type
    • 没有重载 -> ,* 等运行符
    • 有一个prmote方法将弱指针升级为强指针
    • 目标对象的父类不是 LightRefBase,而我 RefBase

    智能指针的套路,大致就是指针在引用的时候或者在析构的时候调用object的增加计数或者减少计数,那么弱指针会有什么不一样,查看其构造函数

    在sp中,构造时会把计数器加1,但在wp中,调用createWeak方法,并且给m_refs赋值,并没有计数器,wp中m_refs充当计数器的功能。

    这个函数属于前面提到的RefBase类,如下所示:

    RefBase嵌套了一个重要的类weak_type,也就是前面的m_refs指针所属的类型,RefBase中也有一个weak_impl类型,从名称上看它是weakref_type的实现类。

    weak_impl中有mWeak和mStrong,分别对应为弱引用计数器和强引用计数器,而且在构造的时候,把弱引用计数器赋值为0,强引用计数器赋值为另一个常量,因为理论上来说,弱引用计数器值大于强引用计数器。

    到目前为止还没有看到createWeak,它定义在RefBase中,查看其实现:

    createWeak先增加了mRefs的弱引用计数值,然后返回这个值。如果还有其它wp指向它,弱引用计数值继续增加

    这个mRefs值被RefBase(object角色)和wp同时引用着,mRefs在RefBase构造时被创建,wp通过调用createWeak方法得到mRefs, 它们之间的关系如下:

    弱指针看起来很复杂,但和强指针相比,只有一点不同,sp的计数器是int值,但wp的计数器是由weakref_impl管理。

    如果有sp指向这个对象呢?

    代码也比较简单,sp指向此对象时,需要增加弱引用计数值,也要增加强引用计数值。因为强引用计数值在初始化的时候被赋值为常量,如果是第一次,还需要加这个常量值,以保证强引用计数值从0开始。

    接下来我们看对象什么时候会被释放:

    当减少强引用计数的时候,先减少强引用计数值,如果强引用计数值已经为0,则删除对象自己,即RefBase,同时还要减少弱引用计数值,查看减少弱引用计数的方法:

    此函数分成两个部分看,上述部分比较简单,只是减少弱引用计数即可。

    这部分与weakref_impl的mFlags值有关,如果弱引用计数值为0,然后根据mFlags值,如果weakref_impl它的mStrong值是常量或者其它情况,分别删除 impl-mBase或者impl,这里就是释放weakref_impl的地方。

    为什么不在RefBase被释放的时候释放weakref_impl呢?因为做不到,当强引用计数值为0的时候,弱引用计数器往往不为0,所以RefBase的析构函数无法生效。

    相关文章

      网友评论

        本文标题:进程能通信——智能指针

        本文链接:https://www.haomeiwen.com/subject/ghdgcftx.html