Shared Pointers using std::shared_ptr

Shared Pointers in Multithreaded Environments

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

Illustration representing computer hardware

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.

Answers to questions are automatically generated and may not have been reviewed.

A computer programmer
Part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, unlimited access

This course includes:

  • 125 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved