Boost logo

Boost :

From: Scott McCaskill (scott_at_[hidden])
Date: 2001-08-22 11:10:43


> The attached emails show a problem with my "thread safe reference
> count". If yours has the same problem, then the advice from
> kaz_at_[hidden] (in the 2nd email) might be helpful to you.
> In particular, if you ever do what I did in the main program in the
> attachment, you'll have to increment the reference count from "outside
> the smart pointer class" just before the pthread_create call to avoid
> the problem, or, as Kaz points out, never pass the address of an auto
> variable, even if its a "thread safe reference counted" SmartPtr.
>

I think we may be getting tripped up a bit on the terminology. In the code
you sent, the problem is not so much with the reference _count_ but with the
concurrent modifications to the smart _pointer_. The reference count is
thread safe*--for example, if two threads simultaneously call inc_nrefs(),
the accesses will be serialized correctly.

OTOH, there is a problem (as was pointed out) with having two threads trying
to modify the same smart pointer concurrently. So far I have always found
it to be a good practice to think of smart pointers as being the same as POD
types when it comes to concurrent modifications--just don't do it without
external serialization.

* -- there may be a potential problem in dec_nrefs() since it will result in
unlocking an already destroyed mutex; I don't recall what behavior POSIX
specifies for this (or if it's defined at all), but you may not have noticed
any problems in that code since it doesn't check return values from the
pthreads calls.

The way I dealt with that problem was to unlock the mutex before doing the
'delete this'. The problem, of course, is that that can introduce a race
condition, but only _if_ anything else (possibly in another thread) has or
could obtain a pointer to the object. This is why I became interested in
making it impossible to ever have a raw pointer to the object. If I can
guarantee that every pointer to the object is a smart pointer, then I know
that when the reference count goes to 0, there really isn't anything else
pointing to the object, and therefore no race condition is possible.
Naturally this also depends on not sharing smart pointers between threads,
but that's necessary anyway as discussed above.

Attached is the intrusive solution I came up with. It's not thread safe,
but that would be trivial to add. The code in main() shows explicitly what
can and cannot be done with this idiom. The main thing I don't like about
it is that classes derived from the base reference-counted object class need
to have their constructors and destructor be private (or protected) and use
factory methods for object creation in order to make it as difficult as
possible to dynamically allocate an object without using a smart pointer,
but there's no way to enforce this requirement using the language (that I've
discovered).




Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk