Archive for the ‘Design Patterns’ Category


Perspective

The intended audience are C++ developers and architects, It is assumed that the reader of this article is familiar with object oriented programming and design.

For the purpose of brevity and clarity, thread synchronization aspect is omitted and not discussed in details in this the article.

Introduction

Comparing to high level languages such as C# & Java, C++ has a substantial disadvantage with memory management, C# & Java automate memory management using garbage collectors where with C++ the developer is responsible for allocating and freeing memory, and this, increase code complexity and the total development and debugging time.

This article describe an approach for achieving pseudo garbage collection using C++, this, reduces development and mainly debugging time while keepingthe fine memory control supported by C++.

Fundamentals

To be able to automate memory allocation we have to keep track of the users of a given memory block/object, once all users are done consuming the memory block/object it can be automatically freed.

Keeping tack of the memory/object references is done using a reference counter, the counter is increased each time a new user is consuming the memory and is decreased when consumption is done, when the counter hits zero the memory block/object is automatically freed.

Implementation guidelines

In-order to achieve automated memory management, each object must implement reference counting and enable it’s users/consumers to control it, this is done by implementing the simple IRefCount interface described at ‘Code Snap 1’ bellow, The ‘AddRef()’ method increase the internal reference count of the object and returns the result while ‘Release’ decrease the reference count, on ‘Release’, when the reference count hits zero the object delete it-self from memory, the following simple code snap illustrate this concept:

01 interface IRefCount {
02     virtual unsigned int AddRef(void) = 0;
03     virtual unsigned int Release(void) = 0;
04 };

Code Snap 1

To guarantee the object life-time will be controlled only by it’s reference count, any other type of instantiation should be prevented, and thus, all IRefCount objects must have their constructors and destructor decelerations defined as non public, instead a special method used for instantiation is to be implemented, in ‘Code Snap 2’ bellow the ‘CreateInstance’ method on line #20 is used exactly for that.

The ‘CreateInstance’ method is responsible for allocating the memory required for the object, adding the first reference by calling ‘AddRef()’ and returning the instantiated object to the caller, similarly, the ‘Release’ method on line #13, is responsible for removing the object from memory when the reference count hits zero, the reference count is maintained by the ‘m_uiRefCount’ variable on line #4.

01 class TestObj : public IRefCount
02 {
03 protected:
04     unsigned int m_uiRefCount;
05         
06     TestObj() : m_uiRefCount(0) {}
07     ~TestObj() {}    
08     
09 public:
10     virtual unsigned int AddRef(void) {
11         return ++m_uiRefCount;
12     }
13     virtual unsigned int Release(void) {
14         unsigned int uiRef = –m_uiRefCount;
15         if(0 == uiRef)
16             delete this;
17         return uiRef;
18     }
19     
20     static bool CreateInstance(OUT TestObj** ppObj) {
21         if(0 == (*ppObj = new TestObj()))
22             return false;
23         (*ppObj)->AddRef();
24         return true;
25     }
26 };

Code Snap 2

There are two main pit-falls with reference counting, the first is a reference that is added and never released: a reference leak, this leads to dangling objects in memory ( a memory leak ), the second is an extra call to ‘Release()’ causing a premature disposal of the object which may lead to future access of an already deleted memory block, these problems can easily be avoided by following few simple rules:

  • Add a reference during assignment.
  • Add a reference for objects returned as output parameters.
  • Make sure always to release the reference when stopped using the object.

The following example illustrate implementation of these simple rules:

01 class SomeClass {
02 protected:
03     IRefCount* m_pObj;
04 public:
05     SomeClass() : m_pObj(0) {}
06    ~SomeClass() {
07        if(0 == m_pObj)
08            return;
08        // No need to hold a reference to the object any-more, release it
08        m_pObj->Release();
09    }
10     void set_Object(IRefCount* pObj) {
11         if(0 != m_pObj) {
12            // Release the reference to the existing object before assigning a new value
13             m_pObj->Release();
14        }
15        if(0 != pObj) {
16             m_pObj = pObj;
17            // Add a reference to account for the assignment
18             m_pObj->AddRef();
19        }
20     }
21     bool get_Object(IRefCount** ppObj) {
22         if(0 == m_pObj)
23             return false;
24         *ppObj = m_pObj;
25        // Add a reference to account for the output variable assignment
26         (*ppObj)->AddRef();
27         return true;
28     }
29 };

Code Snap 3

The SmartPtr class

Making sure object references are added and released as needed is tedious and error prone, it is quite easy to forget to release or add a reference, To avoid that, we will use the SmartPtr class, that encapsulate the reference counting logic, this class is described at Code Snap 4 bellow.

00 template<class T_Interface >
01 class SmartPtr
02 {
03 public:
04     SmartPtr() : m_p(0) {
05     }
06
07     SmartPtr(T_Interface* lPtr) : m_p(0) {
08         if (lPtr != 0) {
09             m_p = lPtr;
10             m_p->AddRef();
11         }
12     }
13
14     SmartPtr(const SmartPtr& sp) : m_p((T_Interface*)sp) {
15         if (m_p)
16             m_p->AddRef();
17     }
18
19     ~SmartPtr() {
20         if (m_p) {
21             m_p->Release();
22             m_p = 0;
23         }
24     }
25
26     operator T_Interface*() const {
27         return m_p;
28     }
29
30     T_Interface& operator*() const {
31         _ASSERT(m_p != 0);
32         return *m_p;
33     }
34
35     T_Interface** operator&() {
36         return &m_p;
37     }
38
39     T_Interface* operator->() const {
40         _ASSERT(m_p != 0);
41         return m_p;
42     }
43
44     T_Interface* operator=(T_Interface* lPtr) {
45         if (lPtr == m_p)
46             return m_p;
47         if (0 != m_p)
48             m_p->Release();
49        if(0 != lPtr)
50             lPtr->AddRef();
51         m_p = lPtr;
52         return m_p;
53     }
54
55     T_Interface* operator=(const SmartPtr& sp) {
56         _ASSERT(&sp != 0);
57         if (0 != m_p)
58             m_p->Release();
59         m_p = (T_Interface*)sp;
60         if (m_p)
61             m_p->AddRef();
62         return m_p;
63     }
64
65     void Attach(T_Interface* lPtr) {
66        if (0 == lPtr)
67            return;
68        if (0 != m_p)
69            m_p->Release();
70        m_p = lPtr;
71     }
72
73     T_Interface* Detach() {
74         T_Interface* lPtr = m_p;
75         m_p = 0;
76         return lPtr;
77     }
78
79     void Release() {
80         if (m_p) {
81             m_p->Release();
82             m_p = 0;
83         }
84     }
85
86     T_Interface* m_p;
87 };

Code Snap 4

The following compares a modified version of Code Snap 3 that use the SmartPtr with the original version of the code that does not use the SmartPtr class, as can be seen, usage of the SmartPtr class considerably reduces the lines of code needed by approximately half, no specialized constructor and destructor are needed and the ‘set_Object’ is reduced to a simple assignment operation.

There is one case however, where the SmartPtr class doesn’t automate reference counting, that is, when a reference to the object is passed an an output variable, this is demonstrated at the ‘get_Object’ method on line #8 at the left pane, in this case, after assigning the value to the output variable the reference count must get manually increased.

Using SmartPtr Not using SmartPtr
01 class SomeClass {
02 protected:
03    SmartPtr m_spObj;
04 public:
05     void set_Object(IRefCount* pObj) {
06        m_spObj = pObj;
07     }
08     bool get_Object(IRefCount** ppObj) {
09         if(0 == m_spObj)
10             return false;
11         *ppObj = m_spObj;
12         (*ppObj)->AddRef();
13         return true;
14     }
15 };
16
17
18
19
20
21
22
23
24
25
26
27
01 class SomeClass {
02 protected:
03     IRefCount* m_pObj;
04 public:
05     SomeClass() : m_pObj(0) {}
06    ~SomeClass() {
07        if(0 == m_pObj)
08            return;
09        m_pObj->Release();
10    }
11     void set_Object(IRefCount* pObj) {
12         if(0 != m_pObj) {
13             m_pObj->Release();
14        }
15        if(0 != pObj) {
16             m_pObj = pObj;
17             m_pObj->AddRef();
18        }
19     }
20     bool get_Object(IRefCount** ppObj) {
21         if(0 == m_pObj)
22             return false;
23         *ppObj = m_pObj;
24         (*ppObj)->AddRef();
25         return true;
26     }
27 };

Code Snap 5

There is however one more limitation we need to solve: In order to achieve the automated memory management logic described in this article, as can be seen at Code Snap 2 above, each and every object must implement reference counting, and this, is cumbersome and time consuming, to solve this we will use the RefCountObj class described bellow.

The RefCountObj class

Code Snap 6 bellow present the RefCountObj class which encapsulate the reference counting logic abstracting out all that is needed from the object but the definition of a reference counting interface, in other words, all that is needed from the object is to have two virtual methods to maintain reference counting, namely ‘AddRef’ and ‘Release’ as described by the ‘IRefCount’ interface for Code Snap 1.

01 template< typename T >
02 class RefCountObj : public T
03 {
04 public:
05     static bool CreateInstance(OUT RefCountObj*& pObj) {
06         pObj = new RefCountObj();
07         return (0 != pObj);
08     }
09
10     static bool CreateInstance(OUT SmartPtr& spObj) {
11         RefCountObj* pObj = 0;
12         bool bRet = RefCountObj::CreateInstance(pObj);
13         if (true == bRet)
14             spObj = pObj;// Adds a reference
15         return bRet;
16     }
17
18     unsigned int AddRef(void) {
19         return ++m_uiRef;
20     }
21
22     unsigned int Release(void) {
23         unsigned int uiRef = –m_uiRef;
24         if (0 == uiRef)
25             delete this;
26         return uiRef;
27     }
28
29     protected:
30         std::atomic_uint m_uiRef;
31
32         RefCountObj() : m_uiRef(0) {}
33         virtual ~RefCountObj() {}
34 };

Code Snap 6

The following demonstrate ‘RefCountObj’ usage, on the right pane is Code Snap 2 added code for instantiation on line #30 of the main function, on the left pane is the same code having RefCountObj used to encapsulate the reference counting logic.
As can be seen ‘RefCountObj’ usage reduced the code to the very basic class definition by abstracting out all reference counting logic, this way, the implemented class encapsulate specific use-cases with no need of dealing with reference counting.

There is one exception to the above mentioned, all objects to be used with automated memory management must have pure virtual ‘AddRef’ and ‘Release’ methods, or, directly inherit from the IRefCount interface defined at Code Snap 1 above, the methods signature must correspond with those defined at ‘RefCountObj’.

Using RefCountObj Not using RefCountObj
class TestObj : public IRefCount
{
protected:
public:
};

void main(void) {
    SmartPtr spObj;
    if(!RefCountObj::CreateInstance(spObj))
        return -1;
    return 0;
}

 
 
 
 
 
 
 
 

 
 
 
 
 
 
 
 

 
 
 
 
 
 

class TestObj : public IRefCount
{
protected:
    unsigned int m_uiRefCount;
        
    TestObj() : m_uiRefCount(0) {}
    ~TestObj() {}    
    
public:
    virtual unsigned int AddRef(void) {
        return ++m_uiRefCount;
    }
    virtual unsigned int Release(void) {
        unsigned int uiRef;
        uiRef = –m_uiRefCount;
        if(0 == uiRef)
            delete this;
        return uiRef;
    }
    
    static bool CreateInstance(TestObj** ppObj)
    {
        *ppObj = new TestObj();
        if(0 == *ppObj)
            return false;
        (*ppObj)->AddRef();
        return true;
    }
};

void main(void) {
    SmartPtr spObj;
    if(!TestObj::CreateInstance(&spObj))
        return -1;
    return 0;
}

Code Snap 7

Main Advantages over std::shared_ptr

  • Higher efficiency: Reference count is implemented by each object and not allocated by the smart pointer as with std::shared_ptr reducing memory fragmentation and emitted assembly code execution time
  • DLL Concurrency: The object must implement allocation and de-allocation of it’s memory, this, guarantee cross DLL safety, hence, an object allocated on the heap of one DLL is guaranteed to be deleted from the same heap where with std::shared_ptr one can set a pointer allocated on one DLL to a std::shared_ptr maintained by another, upon std::shared_ptr deletion of the referred object an invalid heap will be used for deletion, causing a memory leak at best, and a crash on worst

Basic COM with Linux

Posted: April 4, 2015 in Design Patterns
Tags:

Perspective

This article is intended for C++ developers, It is assumed that the reader of this article is familiar with object oriented programming and design.

Windows C++ developers working with COM might find this article useful in leveraging their existing windows knowledge with Linux.

Introduction

While COM is widely used on windows operating systems, it is rarely used with Linux, in this article I will demonstrate a simple & Light weight Linux C++ implementation of the basic COM model.

This article is the first of a series of article discussing object oriented design using COM & C++, The Article start with a short explanation of the basic ideas and follows a simple source code example.

The core concepts are simple and are easy to implement on many platforms other than windows, at it’s very basic, COM solve two main problems, [1] Cross-module Object run-time type information, [2] Object life-cycle management, these are fundamental concepts widely used in numerous projects, COM facilitate a simple yet flexible design pattern to solve these problems.

When to use and when not to use

COM was defined decades ago, Since then, new technologies have emerged considerably reducing development cost comparing to COM, However, while these technologies have proved affective in most of the cases there are cases where performance and resource consumption are critical, in these cases C++/COM prove essential.

Web and big-data applications ( for example ) have many highly optimized frameworks enabling implementation using a higher level language such as C# or Java, however, for specialized applications where performance is critical, development must be done in C/C++, in these cases COM proves efficient, I have been vastly using COM while building multimedia / streaming engines on Windows, Linux and mobile devices.

Fundamentals

Object life-cycle control: Reference counting is used to keep the object alive as long as it is being used, and thus, each of the object consumers ( class, method, … ) increase it’s reference count while it’s using the object ( by calling ‘AddRef’ ), and, reduce the reference count when it has finished using the object ( by calling ‘Release’ ).

Object run-time type information: with COM, objects implement interfaces, each such interface is associated with a unique id, this id is then used by the object consumer ( e.g. calling method ) to query for support of a specific interface, the method implementing this logic is called QueryInterface.

The IUnknown interface

The most fundamental COM construct is the IUnknown interface, this interface must be implemented by every COM object and interface, it define methods for reference count control and run-time type information querying.

interface IUnknown
{
    virtual HRESULT QueryInterface(IN REFIID riid, OUT void** ppvObject) = 0;
    virtual UINT AddRef(void) = 0;
    virtual UINT Release(void) = 0;
};

Object life-cycle control is usually implemented using a class member variable for reference counting, calling AddRef increase the reference count by one while Release decrease the reference count, when the reference count reach zero the object is responsible to clean it-self from memory.

The QueryInterface method is used to query the object for support of a specific interface, implementation of the QueryInterface method involves iterating though the ids list of supported interfaces, if the interface queried is supported is found to be support, the object will increase it’s reference count and return a pointer reference through ‘*ppvObject’, if the queried interface was not found, E_NOINTERFACE is returned.

Implementation guidelines

Since COM object maintain their own life time using reference counting, external object life-time control should be prevented, for example allocating a COM object on the stack will cause it’s allocated resources to be released upon stack frame termination making the reference count mechanism useless and mis-leading.

To ensure the object maintain it’s own life-cycle the COM object constructors and destructor are defined as protected, this prevent the object to get directly created on the stack.

COM object creation is implemented using a special static class method usually called CreateInstance, this method allocate the object, Initialize the reference count and returns the default interface, that interface can later be used to query for other interfaces.

The Sample Code

// {00000000-0000-0000-C000-000000000046}
constexpr GUID IID_IUnknown = { 0x00000000, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } };

interface IUnknown
{
    virtual HRESULT QueryInterface(IN REFIID riid, OUT void** ppvObject) = 0;
    virtual UINT AddRef(void) = 0;
    virtual UINT Release(void) = 0;
};

ComBase.inl

This file contain the most basic definitions comprising basic COM behaviour, Every COM object must implement all of the IUnknown interface methods.

// {00000000-0000-0000-C000-000000000046}
constexpr GUID IID_IRefCountPrinter = { 0x12345678, 0x1234, 0x1234, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 } };

interface IRefCountPrinter : public IUnknown
{
    virtual void PrintRefCount() = 0;
};

HRESULT CreateTester(OUT ITester** ppObj);

Interface.h

This is where we define the specialized interfaces we want our objects to support and the instance creation factory methods ( ‘CreateTexter’ in the example above ).

class TesterObj : public ITester
                , public IRefCountPrinter
{
protected:
    std::atomic_uint m_uiRefCount;

    TesterObj();
    ~TesterObj();

public:
    // IUnknown implementation
    HRESULT QueryInterface(IN REFIID riid, OUT void** ppvObject);
    UINT AddRef(void);
    UINT Release(void);

    // ITester implementation
    void TestMe();

    // IRefCountPrinter implementatin
    void PrintRefCount();

    static HRESULT CreateInstance(OUT IUnknown** ppUnk);
};

TesterObj.h

Here we define a basic COM object implementing our COM interfaces consisting of the ‘TestMe()’ and ‘PrintRefCount()’ methods, we have also defined a class variable named ‘m_uiRefCount’ to keep track of the object reference count, to support multi-threading we have to assure atomic access to the variable, for that ‘std::atomic_int’ is used.

TesterObj::TesterObj()
         : m_uiRefCount(0)
{
    printf(“TesterObj::TesterObj(), ref count = %d\n”, (UINT)m_uiRefCount);
}

TesterObj::~TesterObj()
{
    printf(“TesterObj::~TesterObj(), ref count = %d\n”, (UINT)m_uiRefCount);
}

HRESULT TesterObj::QueryInterface(IN REFIID riid, OUT void** ppvObject) {
    if (0 == memcmp(&riid, &IID_IUnknown, sizeof(GUID)))
        *ppvObject = (IUnknown*)((ITester*)this);
    else if (0 == memcmp(&riid, &IID_ITester, sizeof(GUID)))
        *ppvObject = (ITester*)this;
    else if (0 == memcmp(&riid, &IID_IRefCountPrinter, sizeof(GUID)))
        *ppvObject = (IRefCountPrinter*)this;
    else
        return E_NOINTERFACE;
    AddRef();// A reference to the object is returned via ‘*ppvObject’, add a ref
    return S_OK;
}

UINT TesterObj::AddRef(void) {
    return m_uiRefCount.fetch_add(1) + 1;
}

UINT TesterObj::Release(void) {
    const UINT uiRef = m_uiRefCount.fetch_sub(1) – 1;
    if (0 == uiRef)
        delete this;
    return uiRef;
}

void TesterObj::TestMe() {
    printf(“TesterObj::TestMe(), This is a test!\n”);
}

void TesterObj::PrintRefCount() {
    printf(“TesterObj::PrintRefCount(), Ref count is %d\n”, (UINT)m_uiRefCount);
}

HRESULT TesterObj::CreateInstance(OUT IUnknown** ppUnk) {
    TesterObj* pObj = new TesterObj();
    if (0 == pObj)
        return E_OUTOFMEMORY;
    pObj->AddRef();
    HRESULT hr = pObj->QueryInterface(IID_IUnknown, (void**)ppUnk);
    // if ‘pObj->QueryInterface’ has failed, it doesn’t increase the
    // ref count, and this ‘Release()’ will destruct the object
    pObj->Release();
    return hr;
}

TesterObj.cpp

As seen above, the AddRef and Release methods maintain the object lifetime, AddRef increase the reference count while Release decrease it, when the reference count hits zero the object clean it-self from memory.

The QueryInterface method iterate through all of the supported interfaces to verify support, if the queries interface is supported a pointer of that type is returned to the caller, note that when an interface pointer is retuned to the caller the method will increase the reference count by calling AddRef, this is done to account for the new object referenced returned, it is the responsibility of the caller to Release that reference once the object usage is done.

Instance Creation is implemented using the static method CreateInstance, AddRef bound Release the QueryInterface method to guarantee object destruction upon QueryInterface failure.

HRESULT CreateTester(OUT ITester** ppObj) {
    IUnknown* pUnk = 0;
    HRESULT hr = S_OK;
    if (FAILED(hr = TesterObj::CreateInstance(&pUnk)))
        return hr;
    hr = pUnk->QueryInterface(IID_ITester, (void**)ppObj);
    pUnk->Release();
    return hr;
}

Factory.cpp

The factory method ‘CreateTester’ simply Create the object and query it for the ITester interface.

#include “Interface.h”

int main(int argc, char *argv[])
{
    IRefCountPrinter*    pRefCntPrinter    = 0;
    ITester*            pTester            = 0;
    HRESULT                hr                = S_OK;

    if (FAILED(hr = CreateTester(&pTester))) {
        printf(“failed creating object with hr = 0x%.8x\n”, hr);
        return hr;
    }

    if (FAILED(hr = pTester->QueryInterface(IID_IRefCountPrinter, (void**)&pRefCntPrinter))) {
        printf(“failed Querying for the IRefCountPrinter interface with hr = 0x%.8x\n”, hr);
        pTester->Release();
        return hr;
    }
    pRefCntPrinter->PrintRefCount();
    pTester->TestMe();
    pTester->Release();

    printf(“Object is still alive\n”);
    pRefCntPrinter->PrintRefCount();
    pRefCntPrinter->Release();
    return 0;
}

BasicLinuxCOM.cpp

This is the main program used to instantiate and call upon the COM object methods, bellow is the execution output:

TesterObj::TesterObj(), ref count = 0
TesterObj::PrintRefCount(), Ref count is 2
TesterObj::TestMe(), This is a test!
Object is still alive
TesterObj::PrintRefCount(), Ref count is 1
TesterObj::~TesterObj(), ref count = 0

References

Component Object Model, IUnknown