Kor*_*icz 27 c++ performance boost weak-ptr
我正在为游戏设计一个对象结构,在我的案例中,最自然的组织变成了一棵树.作为智能指针的忠实粉丝我shared_ptr独家使用.但是,在这种情况下,树中的孩子将需要访问它的父母(例如 - 地图上的生物需要能够访问地图数据 - 他们的父母的数据.
拥有的方向当然是地图拥有它的存在,所以拥有它们的共享指针.要从存在中访问地图数据,我们需要一个指向父节点的指针 - 智能指针的方式是使用引用,ergo a weak_ptr.
然而,我曾经读到锁定a weak_ptr是一项昂贵的操作 - 可能这不再是真的 - 但考虑到weak_ptr它将经常被锁定,我担心这种设计注定会失败.
因此问题是:
锁定weak_ptr会有什么性能损失?它有多重要?
Bil*_*eal 13
从Boost 1.42源代码(<boost/shared_ptr/weak_ptr.hpp>第155行):
shared_ptr<T> lock() const // never throws
{
return shared_ptr<element_type>( *this, boost::detail::sp_nothrow_tag() );
}
Run Code Online (Sandbox Code Playgroud)
ergo,James McNellis的评论是正确的; 这是复制构建的成本shared_ptr.
Pav*_*l P 11
使用/取消引用shared_ptr几乎就像访问原始ptr一样,与常规指针访问相比,锁定weak_ptr是一个性能“重”操作,因为此代码必须“线程感知”才能正常工作,以防另一个线程触发释放指针引用的对象。至少,它必须执行某种互锁/原子操作,根据定义,该操作比常规内存访问慢得多。
像往常一样,查看正在发生的情况的一种方法是检查生成的代码:
#include <memory>
class Test
{
public:
void test();
};
void callFuncShared(std::shared_ptr<Test>& ptr)
{
if (ptr)
ptr->test();
}
void callFuncWeak(std::weak_ptr<Test>& ptr)
{
if (auto p = ptr.lock())
p->test();
}
void callFuncRaw(Test* ptr)
{
if (ptr)
ptr->test();
}
Run Code Online (Sandbox Code Playgroud)
通过shared_ptr和原始指针访问几乎是相同的。shared_ptr需要首先加载引用值,这需要比原始版本额外加载一次。
callFunc共享:
调用FuncRaw:
调用FuncWeak:
调用 throughweak_ptr会产生 10 倍以上的代码,并且最多必须经过锁定的比较交换,这本身将比取消引用 raw 或 shared_ptr 花费 10 倍以上的 CPU 时间:
仅当共享计数器不为零时,它才可以加载指向实际对象的指针并使用它(通过调用该对象或创建一个shared_ptr)。
对于我自己的项目,我可以通过#define BOOST_DISABLE_THREADS 在任何提升包括之前添加来显着提高性能
.这避免了weak_ptr :: lock的spinlock/mutex开销,这在我的项目中是一个主要的瓶颈.由于该项目不是多线程的,所以我可以做到这一点.