6

I have a thread A which allocates memory and assigns it to a shared pointer. Then this thread spawns 3 other threads X, Y and Z and passes a copy of the shared pointer to each. When X, Y and Z go out of scope, the memory is freed. But is there a possibility that 2 threads X, Y go out of scope at the exact same point in time and there is a race condition on reference count so instead of decrementing it by 2, it only gets decremented once. So, now the reference count newer drops to 0, so there is a memory leak. Note that, X, Y and Z are only reading the memory. Not writing or resetting the shared pointer. To cut a long story short, can there be a race condition on the reference count and can that lead to memory leaks?

4
  • Interesting that two people used the same documentation to reach opposing conclusions. Commented Apr 21, 2010 at 22:53
  • @Mark: I'd say the docs aren't entirely crystal-clear (not to say they're wrong, just that they're easily misinterpreted). Commented Apr 21, 2010 at 23:11
  • I don't understand why you have bounty your question. The answer is already there :) Commented Apr 28, 2010 at 15:56
  • Hoping for a more descriptive answer with a code snippet perhaps.. just a small incentive, its just 100 points.. Commented Apr 29, 2010 at 17:45

5 Answers 5

12

boost::shared_ptr uses locks (or lock-free atomic access) to ensure that reference counts are updated atomically (even if this isn't clear from the docs page). You can configure away the use of the locks if you're writing single threaded code by defining the macro BOOST_SP_DISABLE_THREADS.

Note that the documentation examples in http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/shared_ptr.htm#ThreadSafety that discuss problems with multiple writes from different threads is discussing those threads acting on the same shared_ptr instances (the shared_ptr objects might be globals in the examples), not different shared_ptr copies that point to the same object, which is the usual use case for shared_ptr's. The example you give in the question (acting on copies that point to the shared object) is thread-safe.

Sign up to request clarification or add additional context in comments.

3 Comments

The comment is exactly correct, but I would also add that calling the destructor of some objects from the "wrong" thread or at the "wrong" time can create the usual sorts of multi-threaded bugs like races and deadlocks. If the destroyed object only frees memory, this shouldn't be a problem. However, destructors that do things like unregistering the doomed object with other parts of the system can definitely cause problems.
@Doug that has nothing to do with shared_ptr, though. It's better to think in terms of locked exclusive access than "it crashed because it was at the wrong place at the wrong time." Whatever resources the destructors access should lock themselves.
@Potatoswatter: Yes, I understand that the problem I raised does not directly have to do with the thread safety of shared_ptr. I don't think of race conditions as "it was in the wrong place at the wrong time". I have found bugs caused by shared_ptrs that lost their last reference on (say) a non-main thread and where the destructor does non-trivial cleanup. That's exactly the same as deleting the pointer manually though - "the same thread safety as raw pointers" as the documentation says.
6

No, according to the documentation, these problems cannot occur:

Different shared_ptr instances can be "written to" (accessed using mutable operations such as operator= or reset) simultaneosly by multiple threads (even when these instances are copies, and share the same reference count underneath.)

3 Comments

I have a question though: accordin to the documentation, mixed situation can lead to undefined beahvior: (...) //--- 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" (...) aren't we in this situation here?
The example below that shows the behavior as 'undefined' when it goes out of scope.
@Grimmy, @Brian: In my understanding in example 4 in the documentation one thread tries to read a shared_ptr variable living in the other thread, while this variable goes out of scope. This would be undefined (and it also would be undefined for other types of variables, not only shared_ptr's). If each thread gets its own copy of the shared_ptr variable, those variables can be used (and go out of scope) independently, even if they point to the same object (like in example 2 in the documentation).
2
+50

Several others have already provided links to the documentation explaining that this is safe.

For absolutely irrefutable proof, see how Boost Smartptr actually implements its own mutexes from scratch in boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp (or your platform's corresponding file).

Comments

1

The documentation says:

Different shared_ptr instances can be "written to" (accessed using mutable operations such as operator= or reset) simultaneosly by multiple threads (even when these instances are copies, and share the same reference count underneath.)

So if none of the threads accesses the pointer objects of the other threads, it should be fine. Please have a look at the examples in the documentation and see which one is relevant in your case.

Comments

-2

The best thing to do would be to upgrade to a TR1 or C++0x shared_ptr, as opposed to the Boost variety. I believe that it's standardised that those MUST be thread-safe.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.