c++ - ::lock() 函数如何在 std::weak_ptr 上工作?
问题描述
当你有一个weak_ptr,你这样做:
std::weak_ptr<int> wp; // Pretend it's assigned to a shared_ptr
if (!wp.expired()) // Equivalent to use_count() != 0
{ /* Here we're not 100% sure the raw pointer is accessible because a shared_ptr from another thread
could have been destroyed, and is in the process of decrementing the use_count from 1 to 0 and calling the deleter.*/
}
另一方面:
std::weak_ptr<int> wp; // Pretend it's assigned to a shared_ptr
if (wp.expired()) Equivalent to use_count() == 0
{ /* Here we are sure that the raw pointer is invalid because of the interesting property that once the use_count is 0 it can't get incremented anymore */
}
如果资源仍然有效,访问指针的正确方法是调用 lock,如果资源有效,它将向资源返回 shared_ptr,如果资源无效,则返回空/null shared_ptr:
if (std::shared_ptr shp = wp.lock())
{// We know the resource is valid, we can use it
}
我不明白的是,根据文档,锁定功能被定义为:
有效返回
expired() ? shared_ptr<T>() : shared_ptr<T>(*this)
,原子执行。
所以如果expired()(相当于use_count() == 0)返回true,那么我们确定指针不能被取消引用,我们得到一个空的shared_ptr。另一方面,如果 expired() 返回 false 我们会返回一个 shared_ptr 到资源,但问题是,正如我上面提到的,当 expired() 返回 true 我们知道指针是错误的,但是当它返回 false 时可能是假阴性,但我们会返回一个 shared_ptr。当我们检查返回的 shared_ptr 时,另一个线程可能仍在写入控制块的过程中,对吧?
当文档说“以原子方式执行”时,这是否意味着每次您想访问weak_ptr时调用lock()方法都使用互斥锁,还是使用原子操作?如果是这样,这样做的性能成本是多少?
我不认为它对计数器使用原子类型,因为我听说过一个经常实现的技巧,我认为这是一种避免使用原子类型/操作的方法:
为所有 shared_ptr 实例添加一个只是一种优化(在复制/分配 shared_ptr 实例时保存一个原子增量/减量)Link。
解决方案
相关的 C++ 语言概念是排序。通常,一个操作在另一操作之前或之后排序 。在这种情况下,“以原子方式执行”意味着没有任何内容排序 after expired()
但排序 before shared_ptr<T>(*this)
。
最后,这确实是一个编译器保证。你的实现库知道如何让编译器做正确的事情。标准库中的锁是类似的;他们还必须确保编译器做正确的事情。真正由库编写者决定如何实现这两者。
性能可能取决于实现,但这是一个非常常见的类。这意味着实施者会关心性能。
推荐阅读
- python - 我正在尝试 webscrape 并将结果输出到 csv 文件中
- google-sheets - 如何有条件地格式化单元格中的文本子集
- scala - Scala 程序集挂在 kubernetes gitlabrunner pod
- moodle - 使用 Moodle API 更改活动插件中的字符串
- javascript - 如何同时滚动两行?
- opengl - 纹理或 UBO 的大小限制,需要帮助找到其他解决方案
- python - 如何向字符串中的空格添加不同的字符?(或用不同的字符或数字替换字符串中的特定单词。)
- ios - pod 规范中 requires_arc 的目的是什么?
- kubernetes - 使用 Vagrant/Ansible 启动多节点 kubernetes 集群无法检测 kubelet 文件
- php - htacess, .{0,10} 有效,.+ 不适用于重定向,给出错误 500