Shared Pointers in Multithreaded Environments

Are shared pointers thread-safe? Can they be used in multithreaded applications?

The shared_ptr class itself is thread-safe, but this doesn't automatically make your application thread-safe.

The reference count on the shared_ptr is incremented and decremented atomically. This means that multiple threads can simultaneously create copies of a shared_ptr, and the shared_ptr will correctly keep track of how many references exist.

However, this doesn't protect the object that the shared_ptr points to. If multiple threads access the pointed-to object, you still need to synchronize those accesses to avoid data races.

Consider this example:

#include <iostream>
#include <memory>
#include <thread>

class Counter {
public:
  void increment() {
    ++count;
  }

  int getCount() {
    return count;
  }

private:
  int count = 0;
};

int main() {
  auto counter = std::make_shared<Counter>();

  std::thread t1([counter]() {
    for (int i = 0; i < 1000000; ++i) {
      counter->increment();
    }
  });

  std::thread t2([counter]() {
    for (int i = 0; i < 1000000; ++i) {
      counter->increment();
    }
  });

  t1.join();
  t2.join();

  std::cout << "Final count is " << counter->getCount() << '\n';
}
Final count is 1054186

In this example, two threads are sharing a Counter object through a shared_ptr. However, the output of this program is undefined. Running the program a second time, our output is likely different:

Final count is 1060707

Even though the shared_ptr is safely shared between the threads, the Counter object is not being accessed in a thread-safe way. The increment operation is not atomic, so the threads can interfere with each other, leading to lost increments.

To fix this, you would need to use a mutex or other synchronization primitive to protect the count variable:

#include <iostream>
#include <memory>
#include <mutex>
#include <thread>

class Counter {
 public:
  void increment() {
    std::lock_guard<std::mutex> lock(mutex);  
    ++count;
  }

  int getCount() {
    std::lock_guard<std::mutex> lock(mutex);  
    return count;
  }

 private:
  int count = 0;
  std::mutex mutex;
};

int main() {/*...*/}
Final count is 2000000

Now, the access to count is protected by a mutex, so the program is thread-safe.

In summary, shared_ptr makes it safe to share ownership of an object between threads, but it doesn't automatically make the object itself thread-safe. That still requires proper synchronization in the object's member functions.

Shared Pointers using std::shared_ptr

An introduction to shared memory ownership using std::shared_ptr

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Deleting a Shared Pointer Twice
What happens if I manually delete a shared pointer twice using the delete keyword?
Creating a shared_ptr to this
Is it okay to create a shared_ptr from the this pointer?
Polymorphism with Shared Pointers
How do shared pointers handle polymorphism? Can I store derived class objects in a shared_ptr of base class type?
Shared Pointer Cyclic References
What happens if two shared pointers reference each other? Will this cause a memory leak?
When to Use Shared Pointers
In what situations should I use shared pointers instead of unique pointers or raw pointers?
Or Ask your Own Question
Get an immediate answer to your specific question using our AI assistant