[Insight-developers] Re: LightObject race condition fix

Dan Mueller dan.muel at gmail.com
Mon Aug 13 17:27:55 EDT 2007


Hi Steve,

Sorry for my poor explanation. It could well be that my understanding
of itkSmartPointer is flawed and causing the confusion --- please bear
with me as I try to explain how I understand the situation.

On 14/08/07, Steve M. Robbins <steve at sumost.ca> wrote:
> On Mon, Aug 13, 2007 at 04:26:15PM +1000, Dan Mueller wrote:
> > I use a similar approach to the vtk/java approach you describe: a
> > managed wrapper object (read 'proxy object') keeps a reference to the
> > underlying C++ object, and when the wrapper object is finalized the
> > native reference can be freed.
> >
> > As I mentioned previously, due to a C++/CLI limitation, the wrapper
> > object can only keep a native pointer to any ITK object, not a
> > SmartPointer. Therefore, I have found on subsequent calls to the
> > wrapper methods the SmartPointer thinks it is going out of scope and
> > frees itself.
>
> OK, now I'm even more confused.  First you say that the wrapper object
> can only keep a native pointer.  Then you talk about "the SmartPointer".
> What SmartPointer?

When I refer to native pointer vs smart pointer I mean the following:

Assume:
const unsigned int Dimension = 3;
typedef unsigned char PixelType;
typedef itk::Image< PixelType, Dimension > ImageType;

then "native pointer" is:
ImageType*

and "smart pointer" is:
ImageType::Pointer

The managed wrapper object can only have native pointer members, for example:
public ref class itkImage_D2 : itkImageBase
{
private:
    // NativeType
    typedef itk::Image< double,2 > NativeType;
    NativeType* m_PointerToNative; //NOTE: NativeType::Pointer is not allowed!

    //...
}

>From my understanding, because m_PointerToNative is a _native_ pointer
and not a _smart_ pointer, when it goes out of scope it is deleted.
Here is a small program to demonstrate what I mean:
#define NativePointer 1

#include "itkImage.h"

const unsigned int Dimension = 3;
typedef unsigned char PixelType;
typedef itk::Image< PixelType, Dimension > ImageType;

#if NativePointer
ImageType* GetImage(void)
{
    ImageType* image = (ImageType*)ImageType::New();
    return image;
}
#else
ImageType::Pointer GetImage(void)
{
    ImageType::Pointer image = ImageType::New();
    return image;
}
#endif

int main( int argc, char * argv[] )
{
    try
    {
        #if NativePointer
            ImageType* image = GetImage();
        #else
            ImageType::Pointer image = GetImage();
        #endif
        std::cout << image << std::endl;
        return EXIT_SUCCESS;
    }
    catch( itk::ExceptionObject & excp )
    {
        std::cerr << "Exception thrown " << std::endl;
        std::cerr << excp << std::endl;
        return EXIT_FAILURE;
    }
}

When #define NativePointer 1 then the image created in GetImage() is
freed when it goes out of scope right after return image. However,
when #define NativePointer 0 then the image created in GetImage() is
freed at the end of the try/catch block (I have crudely verified this
using a breakpoint in itkLightObject.cxx in the UnRegister() method).

> > To combat this, I call Register() on the native ITK
> > pointer within every wrapper method to ensure the wrapped native
> > object is kept alive.
>
> I had envisaged that the wrapper object has a native pointer as a
> member variable, and therefore accessible from each of its methods.
> If you add a reference using this pointer at wrapper construction time
> and remove the reference at wrapper destruction, you should be done:
> no need for calling Register() at each wrapper method.
>
> And no need for SetReferenceCount().
>
> What am I missing?

Because the wrapper object only keeps a _native_ pointer to the ITK
object, when a call is made to a wrapper method the reference goes out
of scope and the object is freed (similar to the example above). To
combat this, I call Register() in every wrapper method, for example:

void WrappedSomeMethod()
{
    m_PointerToNative->SomeMethod();
    m_PointerToNative->Register();
}

As I mentioned in my previous email, what may be happening is that the
call to Register() in the wrapper method increments the reference
count to 2, then it goes out of scope and the reference count is
decremented back to 1, meaning that when the wrapper object is
finalized I could simply call UnRegister() rather than
SetReferenceCount(0). For now I use SetReferenceCount(0) because it is
there. If it is not going to be there, I guess I will have to
investigate the matter further to see if UnRegister() will work (as I
suspect it might).

Please note this whole situation arises due to a limitation with the
C++/CLI language --- in an ideal world I would have no need for
SetReferenceCount(0). Unfortunately, as I have discovered, when
working with Windows you don't live in an ideal world.

Hopeful I have not misunderstood how itkSmartPointer operates and have
clearly explained my situation. Thanks for you patience.

Cheers, Dan


More information about the Insight-developers mailing list