C++ 关于共享ptr参考计数块

C++ 关于共享ptr参考计数块,c++,multithreading,c++11,shared-ptr,lock-free,C++,Multithreading,C++11,Shared Ptr,Lock Free,关于std::shared_ptr控制块,我有两个问题: std::shared_ptr<A> i(new A()); (1) 关于尺寸方面: 如何通过编程找到std::shared\u ptr的控制块的确切大小 (2) 关于逻辑: 此外,boost::shared_ptr提到,它们在控制块的更改方面完全是无锁的。(从boost 1.33.0版开始,shared_ptr在大多数常见平台上使用无锁实现。)我不认为 STD::SyrdYPPTR 遵循相同的规则——这是针对未来的C++版

关于
std::shared_ptr
控制块,我有两个问题:

std::shared_ptr<A> i(new A());
(1) 关于尺寸方面: 如何通过编程找到
std::shared\u ptr
的控制块的确切大小

(2) 关于逻辑
此外,
boost::shared_ptr
提到,它们在控制块的更改方面完全是无锁的。(从boost 1.33.0版开始,
shared_ptr
在大多数常见平台上使用无锁实现。)我不认为<代码> STD::SyrdYPPTR <代码>遵循相同的规则——这是针对未来的C++版本的吗?这是否也意味着
boost::shared_ptr
对于多线程情况来说是一个更好的主意?

控制块没有公开。在我读到的实现中,连续存储删除器(和/或在共享对象的情况下,对象本身)的大小是动态的

通常,它至少包含3个指针大小字段-弱、强计数和删除调用程序

至少一个实现依赖于RTTI;其他人则不然

计数操作在我读过的实现中使用原子操作;请注意,C++不要求原子操作数都是无锁的(我相信没有指针大小的无锁操作的平台可以是一个符合C++平台)。 它们的状态彼此一致,并且它们自身也一致,但是没有试图使它们与对象状态一致。这就是为什么在某些平台上使用原始共享PTR作为写时拷贝PIMPL可能容易出错的原因

(1) 关于大小:如何通过编程找到std::shared\u ptr控制块的确切大小

没有办法。它不能直接访问

(2)关于逻辑:另外,Booo::SyddypTr提到它们相对于控制块的变化完全是无锁的(从升压发布1.33.0开始,SyrdypTR在大多数常见平台上使用了一个无锁的实现)。我认为STD::SyrdY-PTR遵循相同的——这是针对未来的C++版本的计划吗?这是否也意味着boost::shared_ptr对于多线程情况来说是一个更好的主意

绝对不是。无锁实现并不总是比使用锁的实现更好。有一个额外的约束,充其量不会使实现变得更糟,但不可能使实现变得更好

考虑两个同样有能力的程序员,每个人都尽最大努力实现
shared\u ptr
。必须生成一个无锁实现。另一个完全可以自由地使用他们的最佳判断。在其他条件相同的情况下,必须生成无锁实现的实现无法生成更好的实现。充其量,无锁实现是最好的,它们都会产生一个。更糟糕的是,在这个平台上,无锁实现有巨大的缺点,一个实现者必须使用一个。哎呀。

(1) 当然,最好检查实现,但是您仍然可以从程序中进行一些检查

控制块是动态分配的,所以为了确定它的大小,您可以重载新的操作符

然后,您还可以检查std::make_shared是否为您提供了一些控制块大小的优化。 在正确的实现中,我希望这将进行两次分配(objectA和control block):

第一个分配给int-4字节,下一个分配给控制块-24字节

- A(empty):
Requested allocation: 1
Requested allocation: 24
- B(8 ints):
Requested allocation: 32
Requested allocation: 24
看起来控制块(很可能)是24字节

- A(empty):
Requested allocation: 1
Requested allocation: 24
- B(8 ints):
Requested allocation: 32
Requested allocation: 24
以下是使用“共享”的原因:

Make shared:
- int:
Requested allocation: 24
只有一个分配,int+控制块=24字节,比之前少

- A(empty):
Requested allocation: 24
- B(8 ints):
Requested allocation: 48
在这里,我们可以预期56(32+24),但看起来实现是优化的。若使用make_shared,则控制块中不需要指向实际对象的指针,其大小仅为16字节

检查控制块尺寸的其他可能性是:

std::cout<< sizeof(std::enable_shared_from_this<int>);

所以我想说,在我的例子中,控制块的大小是16-24字节,这取决于它是如何创建的。

如果有什么错误或不清楚的地方,我很乐意修改这个问题?(对否决它的人来说)
std::shared\u ptr
是一个模板,因此,由于模板必须对编译器可见,没有任何东西可以阻止您研究编译器的
std::shared_ptr
实现,并找出答案。没错,但如果可能,我希望通过编程实现。您可以查看编译器的
std::shared_ptr
实现。除此之外,我认为std::shared_ptr只是使用原子,所以在这方面是“无锁的”。请注意,理想情况下,如果您能提供帮助,您根本不需要跨线程共享可变日期,在这种情况下,您可能需要更简单的引用计数指针,它不需要原子或锁。@tangy也不能保证
std::shared_ptr
是按照标准原子类型实现的。不管怎样,你为什么在意呢?请注意,Boost报价并不是“完全无锁”;它只是“在最常见的平台上”无锁。@Nicolas是的。这可能只是一个关于实现者认为什么是最好的声明。很难想象在任何现代平台上你会需要或想要一个锁——没有任何线程需要等待任何其他线程的情况。C++11只需要无锁的
std::atomic_flag
,这足以构建锁,但不足以进行无锁引用计数。在标准中加入无锁
std::shared_ptr
要求/保证,理论上会限制哪些平台可以支持一致的C++11实现。我认为这就是原因,并不是说在一个可以实现无锁的普通平台上,锁实际上可能更好。是的,只有
std::atomic_flag
可以保证无锁。在能够做到这一点的目标上的良好实现
- A(empty):
Requested allocation: 24
- B(8 ints):
Requested allocation: 48
std::cout<< sizeof(std::enable_shared_from_this<int>);
16