[Insight-developers] LightObject race condition fix

Karthik Krishnan karthik.krishnan at kitware.com
Wed Jul 11 09:33:29 EDT 2007


Thanks Gaetan:

On 7/10/07, Gaëtan Lehmann <gaetan.lehmann at jouy.inra.fr> wrote:
>
>
> Le 10 juil. 07 à 21:59, Luis Ibanez a écrit :
>
> >
> > Hi Gaetan,
> >
> > Wasnt' the right solution to move the code:
> >
> >   if ( m_ReferenceCount <= 0)
> >    {
> >    delete this;
> >    }
> >
> > inside the mutex locked section ?
> >
>
> Can the mutex be unlocked once destroyed by the delete call ?


I agree with you here.  "delete this" invalidates non-static member vars. So
I doubt if the following code snippet will work.

UnRegister()
{
  m_ReferenceCountLock.Lock();
  m_ReferenceCount--;
  if ( m_ReferenceCount <= 0) { delete this;  }
  m_ReferenceCountLock.Unlock();
}

However I agree with Steve/Luis that access of the resource m_ReferenceCount
be thread safe. One solution would be to use a scoped lock (unlocking is
implemented in its destructor, so it automatically does that when it goes
out of scope).

The code would look like

UnRegister()
{
  ScopedLock lock( m_ReferenceCountLock )
  m_ReferenceCount--;
  if ( m_ReferenceCount <= 0) { delete this;  }
}

--------------------------------

Would a scoped lock class that constructs itself from an
itk::SimpleFastMutexLock be useful ?

Boost uses such a scoped lock in its implementation of shared_ptr.

http://boost.cvs.sourceforge.net/boost/boost/boost/detail/shared_ptr_nmt.hpp?revision=1.5&view=markup
http://boost.cvs.sourceforge.net/boost/boost/boost/detail/atomic_count_pthreads.hpp?revision=1.3&view=markup

Thanks
--k

What
> happens in that case ?
> In the current code (as well as with the proposed patch), delete is
> the last thing ran, which seem to be a quite safe behavior.
>
> Here is the description by Julia of the race condition: "Two threads
> could be un-registering at the same time. The decrement is all fine,
> but as soon as you release the lock, one thread is going to win the
> delete race, and sometime later the second thread is going to examine
> the memory and will attempt delete again because the reference count
> is still zero or < 0. Saving the value before releasing the lock will
> guarantee the value of the reference count."
>
> About the Steve's example, a light object should never get a Register
> () call when m_ReferenceCount is 0, because at that point, the object
> is, or will be, deleted, so it is likely to show a bug in the
> program. The behavior with the patch in that example does not seem
> worth than without the patch - and it doesn't seem better though. In
> that case, I think it's up to the user to keep a smart pointer in a
> safe place so it can be safely referenced in a thread.
>
> The changes made are as small as possible to avoid breaking anything,
> but there are surely some others changes to be made.
>
>
> >
> > --
> >
> > About "volatile" its purpose is to let the compiler
> > know that the variable may change its value for reasons
> > that can not be deduced from the current code context.
> >
> > Its purpose is to prevent the compiler from making
> > optimization decision based on the assumption that
> > the variable is not directly modified by assignment
> > code in the current code context.
> >
> >
> >
> >    Luis
> >
> >
> > ---------------------------
> > Steve M. Robbins wrote:
> >> Hi,
> >> I'm not sure what race conditions Julia Smith has uncovered, but the
> >> first change looks like it creates a worse race.
> >> On Tue, Jul 10, 2007 at 08:51:21PM +0200, Gaëtan Lehmann wrote:
> >>> Index: Code/Common/itkLightObject.cxx
> >>> ===================================================================
> >>> RCS file: /cvsroot/Insight/Insight/Code/Common/itkLightObject.cxx,v
> >>> retrieving revision 1.34
> >>> diff -u -r1.34 itkLightObject.cxx
> >>> --- Code/Common/itkLightObject.cxx      4 Apr 2007 20:04:10
> >>> -0000       1.34
> >>> +++ Code/Common/itkLightObject.cxx      10 Jul 2007 18:41:08 -0000
> >>> @@ -150,12 +150,12 @@
> >>> ::UnRegister() const
> >>> {
> >>>   m_ReferenceCountLock.Lock();
> >>> -  m_ReferenceCount--;
> >>> +  int tmpReferenceCount = --m_ReferenceCount;
> >>>   m_ReferenceCountLock.Unlock();
> >>>
> >>      [***]
> >>>   // ReferenceCount in now unlocked.  We may have a race condition
> >>>   // to delete the object.
> >>> -  if ( m_ReferenceCount <= 0)
> >>> +  if ( tmpReferenceCount <= 0)
> >>>     {
> >>>     delete this;
> >>>     }
> >> Imagine that thread 1 has a reference to a LightObject L with
> >> m_ReferenceCount = 1 and calls L->Unregister().  The test for zero
> >> references happens outside the critical section, so imagine what
> >> happens when thread 2 calls L->Register() while thread 1 is at line
> >> [***].  Thread 2 thinks it has obtained a reference and is going
> >> to be
> >> very unhappy after thread 1 deletes L.
> >> I'm not clear on the semantics of "volatile", so it's not clear to me
> >> whether the other change (marking m_ReferenceCount as volatile) is
> >> sufficient to cure this race in the original code.
> >> If volatile isn't sufficient, why not just "delete this" while
> >> holding
> >> the lock?  You'd also need to worry about threads blocking in
> >> Register()
> >> while the object is deleted.  Presumably SimpleFastMutexLock.Lock()
> >> would have to throw if the lock was destructed.  Or something.
> >> My head hurts.
> >> -Steve
> >> ---------------------------------------------------------------------
> >> ---
> >> _______________________________________________
> >> Insight-developers mailing list
> >> Insight-developers at itk.org
> >> http://www.itk.org/mailman/listinfo/insight-developers
>
> --
> Gaëtan Lehmann
> Biologie du Développement et de la Reproduction
> INRA de Jouy-en-Josas (France)
> tel: +33 1 34 65 29 66    fax: 01 34 65 29 09
> http://voxel.jouy.inra.fr
>
>
>
>
> _______________________________________________
> Insight-developers mailing list
> Insight-developers at itk.org
> http://www.itk.org/mailman/listinfo/insight-developers
>
>
>


-- 
Karthik Krishnan
R&D Engineer,
Kitware Inc.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.itk.org/mailman/private/insight-developers/attachments/20070711/3627e6e9/attachment.htm


More information about the Insight-developers mailing list