c++多线程下崩溃一例分析 ACTIONABLE_HEAP_CORRUPTION heap failure block not busy DOUBLE

news2024/11/15 7:42:41

之前的三个代码接口使用了同一把锁,共享资源的访问是有序执行的没有问题。最近改成各个接口使用单独的锁,结果漏掉了共享资源的保护,于是出现了崩溃。最近与这个崩溃做斗争并定位找到的原因,成功复现了。这里总结下,后续涉及多线程访问的务必考虑周全。

崩溃信息描述

windbg工具分析

srv*C:\symbols*http://msdl.microsoft.com/download/symbols
!analyze -v

 以下是使用windbg工具分析出来的崩溃堆栈信息:

 

堆栈信息表明,发生了堆损坏(heap corruption),可能和双重释放(double free)有关。 

可能的原因

  1. 双重释放(Double Free)

    • 在某些情况下,可能会对同一个内存块进行两次释放操作,这会导致堆损坏和崩溃。
  2. 内存越界访问

    • 在代码中,可能会对内存进行越界访问,例如写入超出分配内存范围的数据,这也会导致堆损坏。
  3. 线程安全问题

    • setCache方法中没有使用,这可能导致多个线程同时修改sendBuffer_,从而引发数据竞争和堆损坏。

成员变量 std::string 非线程安全 

在C++标准库中,std::string 本身并不是线程安全的。尽管 std::string 的某些操作可能是线程安全的(例如,读取操作),但对其进行写操作时,仍然需要使用互斥锁来保护,以避免数据竞争和不一致。

线程安全的操作

  1. 读取操作
    • 多个线程可以同时读取同一个 std::string 对象,因为读取操作不会修改对象的状态。

非线程安全的操作

  1. 写操作
    • 多个线程同时对同一个 std::string 对象进行写操作会导致数据竞争和不一致。

崩溃复现过程

https://www.onlinegdb.com/

多线程执行以下代码,为了复现崩溃,setCache中没有加锁。

/******************************************************************************

Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, Java, PHP, Ruby, Perl,
C#, OCaml, VB, Swift, Pascal, Fortran, Haskell, Objective-C, Assembly, HTML, CSS, JS, SQLite, Prolog.
Code, Compile, Run and Debug online from anywhere in world.

*******************************************************************************/
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include <string.h>

class ProtocolSawtooth {
public:
    struct protocolSendDataType
    {
        uint8_t dt1;
        uint8_t dt2;
        uint8_t dt3;
        uint8_t cmd;
        uint8_t res;
        uint8_t res1;
        uint8_t res2;
        uint8_t res3;
    };

    void setCache(const std::string& data) {
        //std::lock_guard<std::mutex> lock(mutex_);
        char send[50] = {0};
        memcpy(send, &sendDataType_, sizeof(sendDataType_));
        sendBuffer_ = std::string(send, sizeof(sendDataType_));
    }

    const std::string& getCache() const {
        std::lock_guard<std::mutex> lock(mutex_);
        return sendBuffer_;
    }

private:
    protocolSendDataType sendDataType_{};
    std::string sendBuffer_;  // 成员变量
    mutable std::mutex mutex_;  // 互斥锁
};

void threadFunction(ProtocolSawtooth& obj, const std::string& data) {
    obj.setCache(data);
}

int main()
{
    std::cout<<"Hello World\n";
    ProtocolSawtooth obj;

    // 多线程示例
    const int numThreads = 1000;
    std::vector<std::thread> threads;

    for (int i = 0; i < numThreads; ++i) {
        threads.emplace_back(threadFunction, std::ref(obj), "Data from Thread " + std::to_string(i));
    }

    // 等待所有线程完成
    for (auto& thread : threads) {
        thread.join();
    }

    // 获取缓存数据
    const std::string& cache = obj.getCache();
    std::cout << "Cached data: " << cache << std::endl;
    return 0;
}

总结 

如果一个函数在其文档中没有特别注明具备线程安全性,则应该认为它不具备。许多库大量使用了内部的静态数据,除非它是为多线程应用所设计,否则要牢记其内部数据可能没有利用互斥量进行适当的保护。类似,如果类的成员函数在其文档中没有特别注明对于多线程应用是安全的话,则认为它不安全。两个线程去操作相同的对象会引起问题,这是显而易见的,然而,即使两个线程去操作不同的物体依然会引起问题。出于多种原因,许多类使用了内部静态数据或者在多个看上去明显不同的对象间共享实现细则。

一般准则

以下给出几个一般准则:

操作系统提供的API具备线程安全性

POSIX线程标准要求C标准库中的大多数函数具备线程安全性,少数例外会在C标准中注明。

对于Windows提供的C标准库,如果所使用的版本没有问题,而且进行了正确的初始化,他们都是安全的。

C++标准库的线程安全性不是很明确,它在很大程度上依赖于使用的编译器。标准模板库线程安全性的SGI准则作为实际中的标准取得很大进展,但并不是统一的标准。所以在使用时,需充分考虑多线程的并发安全。

其他资源

std string与线程安全_这才是现代C++单例模式简单又安全的实现_51CTO博客_C++ 线程安全 单例模式

https://zhuanlan.zhihu.com/p/705622208 

std::string 线程安全_c++ std::string 线程安全吗-CSDN博客

C++学习网 – 世界上最好的中文C++学习网站

std::string简介 – C++学习网

C++标准库中std::string对象在内存中的分配 - 脉脉

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2098966.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[YM]课设-C#-WebApi-Vue-员工管理系统 (六)前后端交互

Http状态码&#xff1a; 终于也是到了前端 上文提到http状态码 这里详细说一下 1xx 表示临时响应并需要请求者继续执行操作 2xx 成功&#xff0c;操作被成功接收并处理 3xx 表示要完成请求&#xff0c;需要进一步操作。 通常&#xff0c;这些状态代码用来重定向 4…

LiveQing视频点播流媒体RTMP推流服务用户手册-分屏展示:单分屏、四分屏、九分屏、十六分屏、轮巡播放、分组管理、记录加载

LiveQing视频点播流媒体RTMP推流服务用户手册-分屏展示:单分屏、四分屏、九分屏、十六分屏、轮巡播放、分组管理、记录加载 1、分屏展示1.1、分组管理1.1.1、新建分组1.1.2、选择资源1.1.3、编辑分组1.1.4、删除资源 1.2、多分屏1.2.1、选择资源1.2.2、单分屏1.2.3、四分屏1.2.…

【多模态大模型】的正确打开方式——图片

早期痛点 识别图片中的物体&#xff0c;早期可以使用Yolo 但是缺点也很明显&#xff1a; 训练时间长成本高泛华性能差通用识别领域覆盖有限 优点&#xff1a; 特殊领域识别 大模型出现 大模型出现后&#xff0c;一些大模型对接了图片识别相关的模型&#xff0c;实现了图片…

利用衍射进行材料分析--Muad

软件介绍 MAUD是一款免费软件&#xff0c;使用组合 Rietveld 方法分析衍射数据。其功能不仅限于衍射&#xff0c;还包括荧光和反射率。 它可以分析来自 X 射线源以及中子、TOF 和 TEM 电子的数据。相含量和晶体结构、微观结构特征&#xff08;如尺寸和应变&#xff09;、晶体…

沉浸式体验亚马逊云科技上私有化部署零一万物AI大模型

小李哥将继续带大家沉浸式体验亚马逊云科技上的国产AI大模型。最近亚马逊云科技的机器学习模型管理平台Amazon SageMaker JumpStart 上线了由零一万物提供的基础模型 Yi-1.5 6B/9B/34B&#xff0c;这也是首批登陆中国区 Amazon SageMaker JumpStart 的中文基础模型&#xff0c;…

【多线程】并发编程wait和sleep的区别

notyfy、notifyAll、wait的使用&#xff1a;sleep/wait/notify/notifyAll分别有什么作用 背景&#xff1a;之前的博客讲解到了notify的使用&#xff0c;那并发编程的时候&#xff0c;到底该用 sleep还是notify呢&#xff1f;本篇我们来一起梳理一下区别 所属类与方法类型 wait…

vscode+django开发后端快速测试接口(轻量版,免postman安装)

目录 背景 步骤 安装插件 编写测试文件 示例一&#xff1a;get接口类型 示例二&#xff1a;post接口类型 示例三&#xff1a;delete接口类型 如何运行test.http测试文件 背景 在最近工作中涉及到使用Django框架开发后端&#xff0c;写完接口后&#xff0c;不可避免需要…

php法律事务综合管理系统Java律师事务所业务流程管理平台python法律服务与案件管理系统(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…

Java八股文总结一

Java基础 一、JDK、JRE、JVM之间的关系&#xff1f; 1、JDK(Java Development Kit):Java开发工具包&#xff0c;提供给Java程序员使用&#xff0c;包含了JRE&#xff0c;同时还包含了编译器javac与自带的调试工具Jconsole、jstack等。 2、JRE(Java Runtime Environment):Ja…

蔡司小乐圆镜片:自由环面与微柱镜排布助力兼顾舒适与效果

从学习到休闲娱乐&#xff0c;孩子们的日常生活已与电子设备密不可分&#xff0c;视力面临日益严峻的挑战。为了让孩子拥有全视野清晰视觉体验的同时&#xff0c;更有效管理孩子的近视发展&#xff0c;让孩子佩戴蔡司小乐圆镜片&#xff0c;也成为不少家长的首选。 数据统计&am…

opencv图像形态学(边缘检测算法实例)

引言 图像形态学是一种基于数学形态学的图像处理技术&#xff0c;它主要用于分析和修改图像的形状和结构。在OpenCV中&#xff0c;图像形态学操作通过一系列的数学运算来实现&#xff0c;如腐蚀、膨胀、开运算、闭运算等。这些操作在图像处理、计算机视觉和模式识别等领域有着…

Python自动化必会技能-Excel文件读取

01 重点 在自动化测试过程中&#xff0c;经常需要使用excel文件来存储测试用例&#xff0c;那么在表格内设计好了测试用例数据后&#xff0c;如何通过自动化读取呢&#xff1f;此时就需要测试小姐姐动手写“代码”了~ 本文主要介绍通过python来读取表格数据。Python读取表格的…

C语言的函数递归

目录 前言 一、递归是什么&#xff1f; 1. 递归的思想 2. 递归的限制条件 二、递归举例 1. 求n的阶乘 1.1 思路分析 1.2 画图推演 2. 顺序打印⼀个整数的每⼀位 2.1 思路分析 2.2 画图推演 三、递归与迭代 四、求第n个斐波那契数 总结 前言 我们在函数上已经非常…

《父母爱情》:找结婚对象,别只看有房有车有颜,这4个特点更重要!

点击上方△腾阳 关注 转载请联系授权 你好&#xff0c;我是腾阳。 最近&#xff0c;我重温了电视剧《父母爱情》&#xff0c;不禁被剧中人物的情感纠葛和生活琐事深深吸引。 在当今社会&#xff0c;许多人在选择结婚对象时&#xff0c;往往只关注房子、车子、颜值&#xff0…

2020年B题高穿越沙漠教社杯全国大学生数学建模竞赛题目与分析

↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ​ ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓…

DHECDH密钥交互算法

1. 引言 在现代通信中&#xff0c;数据的安全性至关重要。无论是网络浏览、电子邮件&#xff0c;还是移动支付&#xff0c;保护数据不被窃听和篡改都是首要任务。密钥交换是保障通信安全的关键技术之一&#xff0c;其中最著名的两个算法是 Diffie-Hellman (DH) 和 椭圆曲线 Di…

用Python实现时间序列模型实战——Day 8: 季节性ARIMA模型 (SARIMA)

一、学习内容 1. SARIMA 模型的定义与公式推导 SARIMA 模型&#xff1a; SARIMA 模型是扩展了 ARIMA 模型的一种方法&#xff0c;全称为季节性自回归积分滑动平均模型&#xff08;Seasonal AutoRegressive Integrated Moving Average&#xff09;。它结合了 ARIMA 模型的非季…

和字符串有关的经典OJ题——字符串的逆置和字符串的翻转

学习完字符串有关的函数之后&#xff0c;那当然在这个章节有两道经典的子题也要给大家分享一下。 分别是字符串的逆置和字符串的翻转。 一、字符串的逆置&#xff1a; 1. 问题描述&#xff1a; 问题很容易理解&#xff1a;对于用户任意给定的字符串&#xff0c;就比如说是原…

MFC自定义消息实例

1、新建一个SHOW名称的对话框文件 2、在SHOWDlg.h中添加代码 #define WM_Display (WM_USER100)afx_msg LRESULT OnDisplay(WPARAM wParam, LPARAM lParam);3、在SHOWDlg.cpp中添加代码 BEGIN_MESSAGE_MAP(CSHOWDlg, CDialog)...ON_MESSAGE(WM_Display, OnDisplay) END_MESSA…

全面解读 HTTP 缓存机制:200 内存与硬盘缓存、304 状态码

更多内容&#xff1a;孔乙己大叔 在探讨网页性能优化时&#xff0c;HTTP 缓存机制是不可或缺的一环。它不仅能够减少数据传输量&#xff0c;降低带宽消耗&#xff0c;还能显著提升网页的加载速度和用户体验。本文将深入解析 HTTP 状态码 200 和 304 在缓存机制中的作用&#xf…