奇怪的shared_ptr行为

2024-01-05

我发现了一个非常奇怪的行为std::shared_ptr在c++中。 以下示例与标准指针完美配合。

然而使用std::shared_ptr导致这里出现分段错误。 (参见下面的回溯)

我知道,访问std::shared_ptr来自多个线程是不安全的,因此我使用原子操作。即使是经典的锁也无法解决问题。

我在用着gcc version 6.3.0 20170406 (Ubuntu 6.3.0-12ubuntu2) with -Wall -O2 -g and -std=c++17

有谁知道解决方案或为什么代码崩溃?

#include <iostream>
#include <thread>
#include <vector>
#include <mutex>

template <typename T>
class list {
private:
    struct Node {
        T value;
        std::shared_ptr<Node> next;

        Node() : next(nullptr) {}
    };

    std::shared_ptr<Node> head;
public:
    // create dummy-nodes
    explicit list() : head(std::make_shared<Node>()){
        head->next = std::make_shared<Node>();
    };

    void push_front(T val) {
        std::shared_ptr<Node> current;
        std::shared_ptr<Node> next;
        std::shared_ptr<Node> newNode = std::make_shared<Node>();
        newNode->value = val;

        do {
            current = std::atomic_load<Node>(&head);
            next = std::atomic_load<Node>(&current->next);
            newNode->next = next;
        } while (!std::atomic_compare_exchange_weak<Node>(&current->next, &next, newNode));
    }
};

int main(int argc, char* argv[]) {

    list<int> ll;

    std::vector<std::thread> threads;
    const int thread_count = 8;
    const int local_count = 200000;

    std::mutex m;

    for (int i = 0; i < thread_count; i++) {
        threads.push_back(std::thread([&ll, i, local_count, &m]() {
            for (int j = local_count * i; j < local_count * (i + 1); j++) {
                m.lock(); // optional for testing; doesnt solve the problem
                ll.push_front(j);
                m.unlock();
            }

        }));
    }

    for (auto& thrd : threads) {
        thrd.join();
    }

    return 0;
}

gdb 回溯:

0x0000555555555d4e in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x7fffd48eb0e0) at /usr/include/c++/6/bits/shared_ptr_base.h:150
150         _M_dispose();
(gdb) bt
#0  0x0000555555555d4e in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x7fffd48eb0e0) at /usr/include/c++/6/bits/shared_ptr_base.h:150
#1  std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:662
#2  std::__shared_ptr<list<int>::Node, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:928
#3  std::shared_ptr<list<int>::Node>::~shared_ptr (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr.h:93
#4  list<int>::Node::~Node (this=<optimized out>, __in_chrg=<optimized out>) at src/main.cpp:11
#5  __gnu_cxx::new_allocator<list<int>::Node>::destroy<list<int>::Node> (this=<optimized out>, __p=<optimized out>) at /usr/include/c++/6/ext/new_allocator.h:124
#6  std::allocator_traits<std::allocator<list<int>::Node> >::destroy<list<int>::Node> (__a=..., __p=<optimized out>) at /usr/include/c++/6/bits/alloc_traits.h:487
#7  std::_Sp_counted_ptr_inplace<list<int>::Node, std::allocator<list<int>::Node>, (__gnu_cxx::_Lock_policy)2>::_M_dispose (this=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:529
#8  0x0000555555555d51 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x7fffd48eb110) at /usr/include/c++/6/bits/shared_ptr_base.h:150
#9  std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:662
#10 std::__shared_ptr<list<int>::Node, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:928
#11 std::shared_ptr<list<int>::Node>::~shared_ptr (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr.h:93
#12 list<int>::Node::~Node (this=<optimized out>, __in_chrg=<optimized out>) at src/main.cpp:11
#13 __gnu_cxx::new_allocator<list<int>::Node>::destroy<list<int>::Node> (this=<optimized out>, __p=<optimized out>) at /usr/include/c++/6/ext/new_allocator.h:124
#14 std::allocator_traits<std::allocator<list<int>::Node> >::destroy<list<int>::Node> (__a=..., __p=<optimized out>) at /usr/include/c++/6/bits/alloc_traits.h:487
#15 std::_Sp_counted_ptr_inplace<list<int>::Node, std::allocator<list<int>::Node>, (__gnu_cxx::_Lock_policy)2>::_M_dispose (this=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:529
#16 0x0000555555555d51 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x7fffd48eb140) at /usr/include/c++/6/bits/shared_ptr_base.h:150
#17 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:662
#18 std::__shared_ptr<list<int>::Node, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:928
#19 std::shared_ptr<list<int>::Node>::~shared_ptr (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr.h:93
#20 list<int>::Node::~Node (this=<optimized out>, __in_chrg=<optimized out>) at src/main.cpp:11
#21 __gnu_cxx::new_allocator<list<int>::Node>::destroy<list<int>::Node> (this=<optimized out>, __p=<optimized out>) at /usr/include/c++/6/ext/new_allocator.h:124
#22 std::allocator_traits<std::allocator<list<int>::Node> >::destroy<list<int>::Node> (__a=..., __p=<optimized out>) at /usr/include/c++/6/bits/alloc_traits.h:487
#23 std::_Sp_counted_ptr_inplace<list<int>::Node, std::allocator<list<int>::Node>, (__gnu_cxx::_Lock_policy)2>::_M_dispose (this=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:529
#24 0x0000555555555d51 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x7fffd48eb170) at /usr/include/c++/6/bits/shared_ptr_base.h:150
#25 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:662
#26 std::__shared_ptr<list<int>::Node, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:928
#27 std::shared_ptr<list<int>::Node>::~shared_ptr (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr.h:93
#28 list<int>::Node::~Node (this=<optimized out>, __in_chrg=<optimized out>) at src/main.cpp:11
#29 __gnu_cxx::new_allocator<list<int>::Node>::destroy<list<int>::Node> (this=<optimized out>, __p=<optimized out>) at /usr/include/c++/6/ext/new_allocator.h:124
#30 std::allocator_traits<std::allocator<list<int>::Node> >::destroy<list<int>::Node> (__a=..., __p=<optimized out>) at /usr/include/c++/6/bits/alloc_traits.h:487
#31 std::_Sp_counted_ptr_inplace<list<int>::Node, std::allocator<list<int>::Node>, (__gnu_cxx::_Lock_policy)2>::_M_dispose (this=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:529
#32 0x0000555555555d51 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x7fffd48eb1a0) at /usr/include/c++/6/bits/shared_ptr_base.h:150
#33 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:662
#34 std::__shared_ptr<list<int>::Node, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:928
#35 std::shared_ptr<list<int>::Node>::~shared_ptr (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr.h:93
#36 list<int>::Node::~Node (this=<optimized out>, __in_chrg=<optimized out>) at src/main.cpp:11
#37 __gnu_cxx::new_allocator<list<int>::Node>::destroy<list<int>::Node> (this=<optimized out>, __p=<optimized out>) at /usr/include/c++/6/ext/new_allocator.h:124
#38 std::allocator_traits<std::allocator<list<int>::Node> >::destroy<list<int>::Node> (__a=..., __p=<optimized out>) at /usr/include/c++/6/bits/alloc_traits.h:487
#39 std::_Sp_counted_ptr_inplace<list<int>::Node, std::allocator<list<int>::Node>, (__gnu_cxx::_Lock_policy)2>::_M_dispose (this=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:529
#40 0x0000555555555d51 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x7fffd48eb1d0) at /usr/include/c++/6/bits/shared_ptr_base.h:150
#41 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:662
#42 std::__shared_ptr<list<int>::Node, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:928
#43 std::shared_ptr<list<int>::Node>::~shared_ptr (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr.h:93
#44 list<int>::Node::~Node (this=<optimized out>, __in_chrg=<optimized out>) at src/main.cpp:11
#45 __gnu_cxx::new_allocator<list<int>::Node>::destroy<list<int>::Node> (this=<optimized out>, __p=<optimized out>) at /usr/include/c++/6/ext/new_allocator.h:124
#46 std::allocator_traits<std::allocator<list<int>::Node> >::destroy<list<int>::Node> (__a=..., __p=<optimized out>) at /usr/include/c++/6/bits/alloc_traits.h:487
#47 std::_Sp_counted_ptr_inplace<list<int>::Node, std::allocator<list<int>::Node>, (__gnu_cxx::_Lock_policy)2>::_M_dispose (this=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:529
#48 0x0000555555555d51 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x7fffd48eb200) at /usr/include/c++/6/bits/shared_ptr_base.h:150
#49 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:662
#50 std::__shared_ptr<list<int>::Node, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:928
#51 std::shared_ptr<list<int>::Node>::~shared_ptr (this=<optimized out>, __in_chrg=<optimized out>) at /usr/include/c++/6/bits/shared_ptr.h:93
#52 list<int>::Node::~Node (this=<optimized out>, __in_chrg=<optimized out>) at src/main.cpp:11
#53 __gnu_cxx::new_allocator<list<int>::Node>::destroy<list<int>::Node> (this=<optimized out>, __p=<optimized out>) at /usr/include/c++/6/ext/new_allocator.h:124
#54 std::allocator_traits<std::allocator<list<int>::Node> >::destroy<list<int>::Node> (__a=..., __p=<optimized out>) at /usr/include/c++/6/bits/alloc_traits.h:487
#55 std::_Sp_counted_ptr_inplace<list<int>::Node, std::allocator<list<int>::Node>, (__gnu_cxx::_Lock_policy)2>::_M_dispose (this=<optimized out>) at /usr/include/c++/6/bits/shared_ptr_base.h:529

这是智能指针和列表节点的一个经典问题:节点的析构函数是递归的,最终会耗尽堆栈。这就是堆栈跟踪显示的内容:堆栈溢出。

In CppCon 2016:Herb Sutter “C++ 中的无泄漏......默认情况下。” https://youtu.be/JfmTagWcqoE?t=13m他们正是讨论这个问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

奇怪的shared_ptr行为 的相关文章

  • 进程何时获得 SIGABRT(信号 6)?

    C 中进程获得 SIGABRT 的场景有哪些 该信号是否始终来自进程内部 或者该信号可以从一个进程发送到另一个进程吗 有没有办法识别哪个进程正在发送该信号 abort 向调用进程发送SIGABRT信号 就是这样abort 基本上有效 abo
  • OpenCv读/写视频色差

    我试图简单地使用 openCV 打开视频 处理帧并将处理后的帧写入新的视频文件 我的问题是 即使我根本不处理帧 只是打开视频 使用 VideoCapture 读取帧并使用 VideoWriter 将它们写入新文件 输出文件看起来比输入更 绿
  • 使用post方法将多个参数发送到asp.net core 3 mvc操作

    使用 http post 方法向 asp net mvc core 3 操作发送具有多个参数的 ajax 请求时存在问题 参数不绑定 在 dot net 框架 asp net web api 中存在类似的限制 但在 asp net mvc
  • Clang 编译器 (x86):80 位长双精度

    我正在尝试在 x86 Windows 平台上使用本机 80 位长双精度 海湾合作委员会选项 mlong double 80 https gcc gnu org onlinedocs gcc x86 Options html似乎不适用于 cl
  • 暂停下载线程

    我正在用 C 编写一个非常简单的批量下载程序 该程序读取要下载的 URL 的 txt 文件 我已经设置了一个全局线程和委托来更新 GUI 按下 开始 按钮即可创建并启动该线程 我想要做的是有一个 暂停 按钮 使我能够暂停下载 直到点击 恢复
  • 如何从 C# 控制器重定向到外部 url

    我使用 C 控制器作为网络服务 在其中我想将用户重定向到外部网址 我该怎么做 Tried System Web HttpContext Current Response Redirect 但没有成功 使用控制器的重定向 http msdn
  • 基于xsd模式生成xml(使用.NET)

    我想根据我的 xsd 架构 cap xsd 生成 xml 文件 我找到了这篇文章并按照说明进行操作 使用 XSD 文件生成 XML 文件 https stackoverflow com questions 6530424 generatin
  • 无法将类型“System.IO.Stream”隐式转换为“Java.IO.InputStream”

    我提到了一些类似的问题 但没有一个涉及IO 当我使用时 我在java中使用了相同的代码Eclipse 那次就成功了 但现在我尝试在中使用这段代码Mono for Android C 它不起作用 我正在尝试运行此代码来创建一个InputStr
  • 生产代码中的 LRU 实现

    我有一些 C 代码 需要使用 LRU 技术实现缓存替换 目前我知道两种实现LRU缓存替换的方法 每次访问缓存数据时使用时间戳 最后比较替换时的时间戳 使用缓存项的堆栈 如果最近访问过它们 则将它们移动到顶部 因此最后底部将包含 LRU 候选
  • 通过 NHibernate 进行查询,无需 N+1 - 包含示例

    我有一个 N 1 问题 我不知道如何解决它 可以在这个问题的底部找到完全可重复的样本 因此 如果您愿意 请创建数据库 设置 NUnit 测试和所有附带的类 并尝试在本地消除 N 1 这是我遇到的真实问题的匿名版本 众所周知 这段代码对于帮助
  • 如何挤出平面 2D 网格并赋予其深度

    我有一组共面 连接的三角形 即二维网格 现在我需要将其在 z 轴上挤出几个单位 网格由一组顶点定义 渲染器通过与三角形数组匹配来理解这些顶点 网格示例 顶点 0 0 0 10 0 0 10 10 0 0 10 0 所以这里我们有一个二维正方
  • 获取 2 个数据集 c# 中的差异

    我正在编写一个简短的算法 它必须比较两个数据集 以便可以进一步处理两者之间的差异 我尝试通过合并这两个数据集并将结果更改放入新的数据集来实现此目标 我的方法如下所示 private DataSet ComputateDiff DataSet
  • System.Runtime.InteropServices.COMException(0x80040154):[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我在 C 项目中遇到异常 System Runtime InteropServices COMException 0x80040154 检
  • g++ 对于看似不相关的变量“警告:迭代...调用未定义的行为”

    考虑以下代码strange cpp include
  • 有没有一种简单的方法可以让 Visual Studio 2015 使用特定的 ToolsVersion?

    使用特定版本构建项目或解决方案时msbuild我可以使用以下命令选择早期的 net 工具链 toolsversion or tv switch C Program Files x86 MSBuild 14 0 bin msbuild tv
  • 是否可以有一个 out ParameterExpression?

    我想定义一个 Lambda 表达式out范围 有可能做到吗 下面是我尝试过的 C Net 4 0 控制台应用程序的代码片段 正如您在 procedure25 中看到的 我可以使用 lambda 表达式来定义具有输出参数的委托 但是 当我想使
  • 耐用功能是否适合大量活动?

    我有一个场景 需要计算 500k 活动 都是小算盘 由于限制 我只能同时计算 30 个 想象一下下面的简单示例 FunctionName Crawl public static async Task
  • 为什么拆箱枚举会产生奇怪的结果?

    考虑以下 Object box 5 int int int box int 5 int nullableInt box as int nullableInt 5 StringComparison enum StringComparison
  • 结构体指针的动态数组

    我必须使用以下代码块来完成学校作业 严格不进行任何修改 typedef struct char firstName char lastName int id float mark pStudentRecord pStudentRecord
  • 带重定向标准流的 C# + telnet 进程立即退出

    我正在尝试用 C 做一个 脚本化 telnet 项目 有点类似于Tcl期望 http expect nist gov 我需要为其启动 telnet 进程并重定向 和处理 其 stdin stdout 流 问题是 生成的 telnet 进程在

随机推荐