std::shared_ptr 内部结构,弱点数量超过预期

std::shared_ptr internals, weak count more than expected

在Advanced STL系列的一个episode (35:00)中,Stephan T Lavavej展示了_Weaks,值为0的计数器决定何时删除_Ref_count结构, 等于活着的数量 weak_ptr,如果有活着就加 1 shared_ptrs。他解释说这是必要的,因为线程安全:如果 _Weaks 只等于 weak_ptr 的数量,那么当最后一个 weak_ptr 超出范围时,也有必要检查 _Uses, alive shared_ptrs 的计数器,检查是否可以删除_Ref_count。由于缺乏原子性,这是不可接受的。

假设_Uses=存活数shared_ptrs,_Weaks=存活数weak_ptrs,假设我们有以下场景:

在多线程应用程序中,什么会出错,这迫使我们使用 _Weak = 存活数 weak_ptr + (shared_ptr 数 ? 1 : 0) 实施?

想象一下下面的场景。线程A持有一个shared_ptr,线程B持有一个对应的weak_ptr。所以在你的实现中,我们有 _Uses == 1_Weaks == 1.

智能指针析构函数有两种可能的实现方式,但都存在问题。

实现方式一:自减,然后校验

Bweak_ptr被摧毁。递减 _Weaks。我们有 _Uses == 1_Weaks == 0B准备检查_Uses,但是...

上下文切换。

Ashared_ptr被摧毁。递减 _Uses。我们有 _Uses == 0_Weaks == 0。开始销毁 _Ref_count.

上下文切换。

B 现在开始检查 _Uses。为 0。开始销毁 _Ref_count.

两个线程现在都在销毁_Ref_count。不好。

实现方式二:先检查,再自减

Bweak_ptr被摧毁。检查 _Uses。它是 1,不会发生破坏。 B 准备递减 _Weaks,但是...

上下文切换。

Ashared_ptr被摧毁。检查 _Weaks。它是 1,不会发生破坏。递减 _Uses。我们有 _Uses == 0_Weaks == 1。完成。

上下文切换。

B 现在轮到递减 _Weaks。我们有 _Uses == 0_Weaks == 0。无事可做。

我们泄露了 _Ref_count。不好。