Reputation: 375
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_ptr
s, to check if _Ref_count
can be deleted. And this is unacceptable because of lack of atomicity.
Assuming that _Uses
= number of alive shared_ptr
s, _Weaks
= number of alive weak_ptr
s, imagine we have the following scenario:
(_Uses
= 0, _Weaks
= 1): last weak_ptr
goes out of scope, decrement _Weaks
(_Uses
= 0, _Weaks
= 0): if _Uses
is equal to 0, delete _Ref_count
structure
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
Reputation: 171177
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.
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.
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