Boost logo

Boost Users :

Subject: [Boost-users] Thread Safety of shared_ptr
From: Kevin Frey (kfrey_at_[hidden])
Date: 2011-05-01 21:00:04


Hello,

 

I wish to clarify a point on the thread-safety of shared_ptr. I have
read the boost documentation on shared_ptr concerning Thread-Safety and
amongst other things it gives this example (see
http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/shared_ptr.htm for
the full set of examples):

 

   shared_ptr<int> p(new int(42));

 

   //--- Example 1 ---

 

   // thread A

   shared_ptr<int> p2(p); // reads p

 

   // thread B

   shared_ptr<int> p3(p); // OK, multiple reads are safe

 

   <snip...>

 

   //--- Example 4 ---

 

   // thread A

   p3 = p2; // reads p2, writes p3

 

   // thread B

   // p2 goes out of scope: undefined, the destructor is considered a
"write access"

 

Given the nature of how the examples are presented, I have nonetheless
presumed the examples are largely independent of one another, as opposed
to each example being dependent on the results of the previous example.
The specific question I have concerns the implications of the phrase "p2
goes out of scope".

 

I have a situation where I have a shared_ptr< Session > which is
initially created by thread A. Many such objects in fact. A separate
thread B cleans up periodically (the exact scenario is a .NET finaliser
interfacing to native C++ code).

 

It is therefore entirely possible for the following two actions to
happen simultaneously:

 

- Thread A is instantiating a new copy of shared_ptr< Session >, copied
from an existing shared_ptr< Session >.

- Thread B is destroying a shared_ptr< Session >.

 

The above shared_ptrs are all referencing the same reference-counting
object. I do not actually know which shared_ptr will be the one that
actually destroys the underlying Session object (which is the whole
point of me using shared_ptr as my cleanup ends up being
non-deterministic with respect to sequence).

 

Example 4 is very important to me in terms of me understanding exactly
what limitation they are describing. My possible interpretations are:

 

1. p2 goes out of scope under any circumstance. Doesn't matter if the
shared_count is 1 or > 1 prior to the object going out of scope.

2. p2 goes out of scope, resulting in destruction of the underlying
object.

 

In my interpretation of the example, when p2 goes out of scope, it will
not result in destruction of the object, because p2 is a copy of p, and
p is [presumably] still in scope. The outcome should merely be a
decrementing of the reference count.

 

So I'm also at a bit of a loss to understand why an incrementing of a
reference count is not considered a "write access" but a potential
simple decrementing of a reference count (occurring via the shared_ptr
destructor) is considered a "write access".

 

In my example I know I will never have thread A attempting to increment
the ref count whilst thread B is potentially destroying the object
simultaneously. When I get to my final copy of my object (ie. unique( )
is true), thread A is guaranteed to not be accessing or copying the
shared_ptr when thread B commences the destruction of the final copy.

 

Will shared_ptr behave correctly or not in my situation?

 

Because if I take the boost example on simple face value, that I cannot
have one shared_ptr going out of scope (and decrementing the ref count)
whilst another thread is incrementing the ref count, then I'm feeling at
a loss why boost would go to the trouble of a lock-free implementation
in the first-place, since I would have thought my example is a pretty
common (almost canonical) of why you would want thread-safety for
shared_ptr. Now I'll be the first to admit that the boost guys are a lot
smarter than me, so I'm hoping my understanding of the capability is
simply wrong.

 

(The problem for me is that if shared_ptr does not provide the
thread-safety requirements I need, then I must achieve that
thread-safety external to shared_ptr with some kind of mutex, which puts
me in a conundrum as to where such a mutex would be held. The obvious
place would be my Session object since it provides the perfect
granularity, but then I have the situation of having an object, which
might potentially get deleted [when the last shared_ptr is destroyed],
having a mutex referenced within it for the purpose of locking, which is
clearly wrong.)

 

Any help will be greatly appreciated.

 

Thanks

 

Kevin

 



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net