C++: 智能指针 sp 之 Android轻量级智能指针

上一节手动实现智能指针最后实现的智能指针还存在缺陷,那就是RefBase中对引用计数的操作是非原子操作,有可能会被打断,是非线程安全的。
Android实现的对引用计数线程安全实现LightRefBase如下:

frameworks/rs/cpp/util/RefBase.h

template <class T>
class LightRefBase
{
public:
    inline LightRefBase() : mCount(0) { }
    inline void incStrong(__attribute__((unused)) const void* id) const {
        __sync_fetch_and_add(&mCount, 1); //(1)
    }
    inline void decStrong(__attribute__((unused)) const void* id) const {
        if (__sync_fetch_and_sub(&mCount, 1) == 1) { //(2)
            delete static_cast<const T*>(this); //(3)
        }
    }
    //! DEBUGGING ONLY: Get current strong ref count.
    inline int32_t getStrongCount() const {
        return mCount;
    }

    typedef LightRefBase<T> basetype;

protected:
    inline ~LightRefBase() { }

private:
    friend class ReferenceMover;
    inline static void moveReferences(void*, void const*, size_t,
            const ReferenceConverterBase&) { }

private:
    mutable volatile int32_t mCount;
};

可以看到Android class LightRefBase中对引用计数mCount的(1)加1操作和(2)减1操作都是原子的。并且(3)中当引用计数减1结果为0时将目标对象销毁。这里值得一提的是待操作的目标对象的类一般是继承LightRefBase类的,所以这里static_cast向下转换成目标对象,再目标对象delete。

修改上一节最后的文件,使用Android轻量级智能指针LightRefBase:

#include <iostream>
#include <string.h>
#include <unistd.h>
#include "RefBase.h"

using namespace std;
using namespace android::RSC;

class Person : public LightRefBase<Person>{

public:
    Person() {
        cout <<"Pserson()"<<endl;
    }

    ~Person()
    {
        cout << "~Person()"<<endl;
    }
    void printInfo(void)
    {
        cout<<"just a test function"<<endl;
    }
};

template<typename T>
void test_func(sp<T> &other)
{
    sp<T> s = other;
    cout<<"In test_func: "<<s->getStrongCount()<<endl;
    s->printInfo();   
}

int main(int argc, char **argv)
{    
    int i;

    /* 少用"Person *"; 用"sp<Person>"来代替"Person *"
     * Person *per; 
     * 有2种操作: per->XXXx, (*per).XXX
     * sp也应该有这2中操作:
     *            sp->XXX, (*sp).XXX
      */
    sp<Person> other = new Person();

    (*other).printInfo();
    cout<<"Before call test_func: "<<other->getStrongCount()<<endl;

    for (i = 0; i < 2; i++)
    {
        test_func(other);
        cout<<"After call test_func: "<<other->getStrongCount()<<endl;
    }
    return 0;
}

现在回过头看上面Android RefBase.h中class LightRefBase的实现,其中
但是,Android轻量级智能指针 LightRefBase也只是保证对引用计数的操作是原子性的,而无法保证对目标对象的操作也是安全的。比如其中decStrong将引用计数减为0时紧接着delete目标对象的操作就是非安全的:
上面的LightRefBase代码(2)和(3)之间不是原子的–中间有可能被其他线程切换出去,抢占的线程中可能会执行类似"sp<Person> s3 = s;",这需要程序员自己去考虑。

总结一句话:Android轻量级指针 LightRefBase 通过原子操作确保了引用计数操作的线程安全,但是无法保证对目标对象的销毁同样如此。


参考:韦东山C++教程

©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页