user2551229
user2551229

Reputation: 375

std::shared_ptr internals, weak count more than expected

In one episode (35:00) of Advanced STL series, Stephan T Lavavej showed that _Weaks, the counter whose value of 0 determines when to delete the _Ref_count structure, equals the number of alive weak_ptr, plus 1 if there are alive shared_ptrs. He explained that it is necessary because of thread safety: if _Weaks only equaled the number of weak_ptr then when last weak_ptr would go out of scope it would be also necessary to check _Uses, the counter of alive shared_ptrs, to check if _Ref_count can be deleted. And this is unacceptable because of lack of atomicity.

Assuming that _Uses = number of alive shared_ptrs, _Weaks = number of alive weak_ptrs, imagine we have the following scenario:

What, in multithreaded application, can go wrong, which forces us to use _Weak = number of alive weak_ptr + (number of shared_ptr ? 1 : 0) implementation?

Upvotes: 11

Views: 3986

Answers (1)

Imagine the following scenario. Thread A holds a shared_ptr, thread B holds a corresponding weak_ptr. So in your implementation, we have _Uses == 1 and _Weaks == 1.

There are two possible implementations for the smart pointer destructors, both with problems.

Implementation 1: decrement, then check

B's weak_ptr is destroyed. Decrements _Weaks. We have _Uses == 1, _Weaks == 0. B prepares to check _Uses, but ...

Context switch.

A's shared_ptr is destroyed. Decrements _Uses. We have _Uses == 0, _Weaks == 0. Begin destruction of _Ref_count.

Context switch.

B now get round to checking _Uses. It's 0. Begin destruction of _Ref_count.

Both threads are now in the process of destroying _Ref_count. Not good.

Implementation 2: check, then decrement

B's weak_ptr is destroyed. Check _Uses. It's 1, no destruction will happen. B prepares to decrement _Weaks, but ...

Contex switch.

A's shared_ptr is destroyed. Checks _Weaks. It's 1, no destruction will happen. Decrement _Uses. We have _Uses == 0, _Weaks == 1. Done.

Context switch.

B now gets round to decrement _Weaks. We have _Uses == 0, _Weaks == 0. Nothing else to do.

We have leaked the _Ref_count. Not good.

Upvotes: 10

Related Questions