We help IT Professionals succeed at work.

Smart Pointers and Multithreading

JHaack asked
Medium Priority
Last Modified: 2013-11-20
I have a SmartPtr class that implements reference counting and garbage collections. First of all, I am weary about it's completeness.  Is there a complete SmartPtr class that acts exactly (or nearly) like a regular pointer available.  Second, since threads each have their own stack, are smart pointers useful for multithreading?  It seems to me that since threads share resources (heap, GDI, etc), the smart pointer would be ideal for multithreading memory management.  Ultimately, I'm looking for a complete smart pointer and a good discussion (or book/article) on the various uses of smart pointers, including their applicability to multithreading.
Watch Question

Tommy HuiEngineer

One good reference I saw is in Scott Meyer's More Effective C++: Item 28 on page 159. Actually, his books are really good (Effective C++).


I'm looking for the application of smart pointers in multithreading.  I agree that "More Effective C++" is a good reference on smart pointers, but it doesn't really provide me with any information that I didn't already know.  As I indicated in the question, I have already implemented a smart pointer.  Beyond that, I'm looking for a commercial-level/standard smart pointer and, most importantly, a discussion on the application of smart pointers in multithreading.
I've implemented smart pointer classes before for multithreaded environments. The only change you need to make for multithreading to the basic smart pointer idiom is wrap each increment and decrement/check with some sort of synchronization primitive. A good candidate on Win32 for these operations are InterlockedIncrement/InterlockedDecrement. (On non-Win32 platforms, you could use a semaphore for the ref count, or wrap your increments/decrements with a mutex.)

So your base reference-counted object would look something like this: (I've simplified it for brevity)

class CRefObject
{ public: void AddRef() { InterlockedIncrement(&m_refCount); }
          void Release() { if(InterlockedDecrement(&m_refCount) == 0) { DeleteThisObject(); }
  private: long m_refCount;

Then, assuming your existing smart pointer class already called the AddRef()/Release() routines, you really don't need any changes to your smart pointers unless you share them between threads. In that case, you must wrap the smart pointers copy constructors/assignment operators/anything that can change what the smart pointer points to with some sort of syncronization (a critical section in Win32 would do nicely).

Now I have to convince you why this is thread safe. The Interlocked* routines prevent this situation:

Object meef has a ref count of 2 because each thread has a smart pointer which references it. Both threads are simultaneously trying to create another reference to the object by copying their respective smart pointers into new smart pointers. Here is a time line of their actions through the copy constructors of the smart pointers (time goes down):

    Thread 1               Thread 2
    fetches ref count (temp= 2)
    increments it (temp++)        
    (task switch)
                           fetches ref count (temp = 2)
                           increments it (temp++)
                           stores ref count (meef.refCt = 3 now)
                           (task switch)
    stores ref count (meef.refCt = 3 now)

Note that the ref count should be 4, but its 3 because of inopportune task switching. The Interlocked* routines make the increments and decrements/checking atomic, so this can't happen.

Now, when I first started thinking about these issues I was convinced that there could be a case where one thread would decrement the ref count to zero, while at the same time another thread wants to increment the ref count by one, so the object gets deleted when it shouldn't. But further analysis shows that this should never happen - because the second thread should NOT have a smart pointer to the object in the first place, and thus can't increment its ref count at all (because remember, at the beginning of this whole situation, the ref count of the object would have to be at 1. Which means the first thread's smart pointer is the only reference to that object, and once that reference is released, the object should rightly be deleted).

Another interesting issue is when you have a smart pointer that is shared between multiple threads, i.e. you have a shared data area that contains a smart pointer. But I've decieded that this presents no problem - as long as the smart pointer is only created once and deleted once, it should be fine. The key is to remember is the reference is held with the smart pointer, not with the thread itself.

I also was able to get the syntax of using the smart pointer to be consistent with normal pointer syntax for every case except for casting to a derived class. Let me illustrate:

Normal method:  pMeef = (CMeef *) pFoo; // pFoo is a pointer to a base type of pMeef
Smart Pointer method pMeef = (CMeef *) (CFoo *) pFoo; // pFoo is a smart pointer to a base type of pMeef

I don't have the code handy but I could post it later if you want.

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts

whoops, it screwed up my spacing on the timeline:

Thread 1: fetches ref count (temp= meef.m_nRefCount; // == 2)
Thread 1: increments it (temp++)
(task switch)
Thread 2: fetches ref count (temp = meef.m_nRefCount; // == 2)
Thread 2: increments it (temp++)
Thread 2: stores ref count (meef.m_nRefCount = temp; // == 3)
(task switch)
Thread 1: stores ref count (meef.m_nRefCount = temp; // == 3!!)



I'm pretty sure I can synchronize my smart pointer to be thread safe.  However, I am a little unclear about how to share smart pointers between threads.  I've always used handles to create shared pointers.  Isn't there a problem in passing pointers between threads?  Specifically, I want to allocate data on the heap using a smart pointer in the primary thread.  Secondary threads will then use the heap data, incrementing the refcount when they start and decrementing it when they finish - not worrying about whether the heap should be freed.  If you could provide a snippet of code that illustrates the concept, I would greatly appreciate it.  Otherwise, thank you for the excellent help that you've already provided.

P.S.  Do you know of any good articles/books on smart pointers and multithreading?

I haven't run across any articles or books that deal with smart pointers in a multithreaded context.

generally, this is how I would go about the scenario you describe (this isn't garuanteed to be syntactically correct, but it is conceptually correct):

struct ThreadArgs
  MeefSmartPointer ptr; // MeefSmartPointer is a smart pointer to
                        // type CMeef

void thread1(void *pArg)
  ThreadArgs *p = (ThreadArgs *)pArg;
  MeefSmartPointer ptr = p->ptr; // meef ref count == 3
  delete p; // free up arguments // meef ref count == 2
   // do our thing with our reference to the shared data in ptr
  // when we exit, we decrement meef's ref count

#define STACK_SIZE (1<<14) // stack size of 16K
void main()
  MeefSmartPtr ptr = new CMeef; // increments ref count to 1

  ThreadArgs *p = new ThreadArgs;
  p->ptr = ptr; // ref count = 2 now
  _beginthread(thread1, STACK_SIZE, (void *)p);
  // worker thread deletes arguments
    // do our main thread thing
  // when we exit, we decrement the meef's ref count

This allows both threads to acces the data (the CMeef object) and keeps a reference count to it. As long as the ref counting is implemented as I described above, this is thread safe. Note that since we're never really sharing a smart pointer between two threads (i.e. the main thread and thread1 do not access the passed smart pointer itself at the same time, only the CMeef object), you don't need to worry about synchronizing the smart pointer's copy constructors/assignment operators.

Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.


Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.