Multithreaded Programming with shared_ptr and Atomic References
Learn safe and efficient multithreaded programming using shared_ptr and atomic references with an example.
Using shared_ptr in a multithreaded environment
What about the std::shared_ptr? Can it be used in a multithreaded environment, and how is reference counting handled when multiple threads are accessing an object referenced by multiple shared pointers?
To understand shared pointers and thread safety, we need to recall how std::shared_ptr is typically implemented. Consider the following code:
// Thread 1auto p1 = std::make_shared<int>(42);
The code creates an int on the heap and a reference-counted smart pointer pointing at the int object. When creating the shared pointer with std::make_shared(), a control block is created next to the int. The control block contains, among other things, a variable for the reference count, which is incremented whenever a new pointer to the int is created and decremented whenever a pointer to the int is destroyed. To summarize, when the preceding code line is executed, three separate entities are created:
- The actual
std::shared_ptrobjectp1(local variable on the stack) - A control block (heap object)
- An
int(heap object)
The following figure shows the three objects:
Now, consider what would happen if the following code was executed by a second thread:
// Thread 2auto p2 = p1;
We are creating a new pointer pointing at the int (and the control block). When creating the p2 pointer, we read p1, but we also need to mutate the control block when updating the reference counter. The control block lives on the heap and is shared among the two threads, so it needs synchronization to avoid data races. Since the control block is an implementation detail hidden behind ...