• 3.8 C++高级编程_Android轻量级指针


    上一节我们使用了一个智能指针的方法,来防止C++中由于申请的内存未释放引起的内存泄漏的问题。

    但是,上一节的代码中还有一些问题,是什么问题呢?

    在上一节的代码中,我们定义了一个基类RefBase,在RefBase中定义了一个引用计数count,还有一些列count加1和减1操作。

    问题就出在这个加一操作和减一操作上面,它们并不是原子操作,即它们实际上是通过几个指令完成的。

    以加一操作为例,count++ 实际上是分成三步完成的:

    1. 将count的值从内存读到寄存器中;
    2. 将寄存器中的count值加1;
    3. 将寄存器中加1后的count值写回内存;

    创建了一个sp类,那么对应的会有一个 count 计数值产生。

    假设有A,B两个进程都会使用这个sp类,那么就可能出现下面的情况,初始的count值为1:

    1. A进程:将count的值从内存读到寄存器中;(内存中的count = 1)
    2. A进程:将A进程寄存器中的count值加1;(内存中的count = 1,A进程寄存器中的count = 2)
    3. 此时,出现第一次进程切换,切换到了B进程;
    4. B进程:将count的值从内存读到寄存器中;(内存中的count = 1)
    5. B进程:将B进程寄存器中的count值加1;(内存中的count = 1,B进程寄存器中的count = 2)
    6. B进程:将B进程寄存器中加1后的count值写回内存;(内存中的count = 2)
    7. 第二次进程切换,切回A进程;
    8. A进程:将A进程寄存器中加1后的count值写回内存;(内存中的count = 2)

    (所谓的A进程寄存器和B进程寄存器从物理上说是相同的寄存器,但是他们在不同时刻存放的值不同。)

    内存中的count值在经过A,B两个进程的引用后,应该为3,但是此时结果却为2。

    出现这样情况的原因就在于,count++的操作不是一个原子操作,一旦在操作的过程中被打断,且在打断过程中有别的进程对 count 值进行操作,那么就可能出现错误。

    这种在多进程情况下可能出现问题的代码,也叫作非线程安全代码

    想要修改为线程安全代码,可以将count加一和减一变为原子操作

    安卓源码中就有类似操作。

    其中__sync_fetch_and_add 和__sync_fetch_and_sub 就是不可以被打断的原子操作,并且__sync_fetch_and_sub 返回的是mCount减一之前的值

    修改代码,使用安卓源码中的 LightRefBase。

    LightRefBase是一个模板。

     

     将代码中的sp类删除,使用安卓源码中的sp类。

    编译测试,程序正常执行。

    需要注意一点是,在之前的代码中,我们在sp类的析构函数中,执行delete操作。

    但是在安卓轻量级指针中,是在RefBase 中执行的 delete操作。

    最后,需要说明一下安卓轻量级指针并不是完美的,它仅仅只是对count计数值做了原子操作,对于这个对象本身并不是线程安全的,因为delete操作并不是线程安全的

    本节代码比较简单,主要是认识和使用一下安卓轻量级指针。

    本节代码可以通过git下载:

    1. git clone https://github.com/weidongshan/cpp_projects.git
    2. git checkout v20
  • 相关阅读:
    iOS 16 SwiftUI 4.0 列表(List)项分隔线变短的原因及解决
    【Python入门与进阶】综合练习题:学生成绩管理系统
    通讯网关软件003——利用CommGate X2Mbt实现Modbus TCP访问OPC Server
    经典网络解(三) 生成模型VAE | 自编码器、变分自编码器|有监督,无监督
    默认搜索引擎怎么变成百度呀,谁能告诉我
    转置后再排列整理
    AI:08-基于深度学习的车辆识别
    最短路径算法
    CVPR2022 | 可精简域适应
    基于python命令流及代码的Plaxis自动化建模
  • 原文地址:https://blog.csdn.net/qq_33141353/article/details/126476149