Saturday, March 31, 2012

Android's C++ reference counting

#include <stdio.h>
#include "android/os/Ref.h"

using namespace android::os;

class RefTest : public Ref {
public:
    RefTest(int32_t id) : mID(id) {
        printf("RefTest ctor: %d\n", mID);
    }

    virtual ~RefTest() {
        printf("RefTest dtor: %d\n", mID);
    }

    int32_t id() const {
        return mID;
    }

private:
    int32_t mID;
};

int main() {
    sp<RefTest> ref1 = new RefTest(1);

    {
    sp<RefTest> ref2 = new RefTest(2);
    }

    wp<RefTest> ref3 = ref1;
    sp<RefTest> ref4 = ref3.toStrongRef();
    if (ref4 == NULL) {
        printf("RefTest object is destroyed\n");
    } else {
        printf("RefTest object %d is still around\n",
            ref4->id());
    }
    ref4 = NULL;

    ref1 = NULL;
    ref4 = ref3.toStrongRef();
    if (ref4 == NULL) {
        printf("RefTest object is destroyed\n");
    } else {
        printf("RefTest object %d is still around\n",
            ref4->id());
    }

    return 0;
}

To use the reference counting mechanism for (non Android) C++ projects check out the Ref class of my native Android messaging and concurrency framework. It contains Google's C++ reference counting class from the Android project along with some fixes and refactorings for code readability.

To get started you have to inherit (virtual) public from the Ref base class so that each object of a particular class that derives from Ref contains reference counters and the necessary management methods to increment and decrement them.
Afterwards you are able to create instances of types like RefTest as in the example above and assign them to strong (smart) pointers of type sp<RefTest>. There also is a wp<> template class for weak pointers when you have to get around circles of strong references.

Each Ref object has a WeakRefImpl object that keeps two reference counters, one for weak references and one for strong references. Whenever the strong reference counter is incremented or decremented then the weak reference counter also gets incremented or decremented. But when you create a wp<> to some object only the object's weak reference counter is incremented. Therefore, managed objects live as long as there is some strong pointer referring to it. However, the managed object's WeakRefImpl object may live longer than the object itself because it lives as long as there is some weak pointer referring to the object. If that is the case and the object itself is already destroyed the weak pointer's toStrongRef method returns NULL to indicate that the object is not available anymore.

The Ref base class is thread-safe without needing expensive locks. It completely synchronizes the access to the reference counters using atomic operations. The sp<> and wp<> template classes are not thread-safe. So always make sure you copy the strong and weak pointers when you share managed objects with different threads.

The C++0x shared_ptr class is similar to Android's C++ reference counting class but there are also some differences. E.g. while C++0x keeps the reference counter outside of the managed object in the shared_ptr class Android's reference counting mechanism keeps the counter in the object itself.

9 comments:

  1. hi ,
    which design pattern are they using in refbase.h in android

    ReplyDelete
    Replies
    1. I don't think Google is using a particular design pattern in Android's RefBase class. The cool thing about Android's reference counting mechanism is that the counter lives within the RefBase base class. Therefore the sp<> and wp<> reference pointers can be created any time from a RefBase object and the sp<> and wp<> classes do not need to be thread safe. RefBase can be implemented with just atomic integers.

      Delete
    2. Thanks for your reply Daniel , I had gone through the refbase.h & refbase.cpp , but still i did n't understand one thing how they are calling the constructor of refbase class bcoz all refbase class constructors either under private or protected access, there is no static function also. could you please explain abt this , yeterday i tried a lot to understand the concept but failed , plz help on this part .

      Thanks
      vinay

      Delete
    3. Ah ok. To make the C++ copy ctor and assignment operator private is a pattern to just disallow this operations on RefBase objects. You often do this to avoid calling one of this "heavy" operations accidentally, as you can see here: http://mjibrandl.blogspot.de/2010/06/disable-copy-constructor-and-assignment.html.
      Making the standard ctor and dtor protected is no big thing since every managed object has to inherit form RefBase and therefore it is possible for them to call the protected ctor and dtor. Furthermore you disallow creating plain RefBase objects, so you can only create managed objects that derive from RefBase.

      Delete
    4. thats fine but in refbase.h even default constructor and disctructor also under protected , then how it is possible to call the Refbase constructor

      Delete
    5. Every C++ object can call the protected methods from its base class. The same is also true for a ctor and dtor. Since a managed object always has to inherit from RefBase it can call the protected ctor and dtor from the RefBase base class. Be aware, that the base class ctor and dtor are called automatically by the derived managed object during construction and destruction. So only derived classes can call the RefBase ctor and dtor.

      Delete
  2. thank you very much for your explanation Daniel

    ReplyDelete
  3. Hi Daniel , Thanks a lot for such a good tutorial on sp and wp. I have a question -- why there is a need to keep the WeakRefImpl object of Managed object , even if Managed object is no longer accessible means destroyed. what operation can we do with wp of this destroyed managed object .

    ReplyDelete
    Replies
    1. The WeakRefImpl object is needed as long as there are weak references. Otherwise all weak references would be broken and make a program crash.

      Delete