pthread多线程: 线程泄漏的检测

news/2024/11/9 3:17:43/

文章目录

    • 1. 目的
    • 2. 什么是线程泄漏
    • 3. pthread 线程泄漏例子
      • 3.1 代码
      • 3.2 编译和运行
      • 3.3 简要分析
    • 4. 检测线程泄漏
      • 4.1 编译链接时传入参数 `-fsanitize=thread`
      • 4.2 确认 TSAN_OPTIONS 环境变量
    • 5. 修复线程泄漏
      • 5.1 方法1: 主线程等待子线程
      • 5.2 方法2:子线程主动脱离主线程

在这里插入图片描述

1. 目的

线程泄漏是使用多线程时容易出现的一个错误, 这和内存泄漏有点像:操作系统为创建过程消耗了资源,但没有回收, 如果频繁的创建那么系统被严重拖累, 新申请线程或内存的成功概率降低。

2. 什么是线程泄漏

使用 pthread 实现多线程任务调度时, 子线程是从主线程创建的, 如下两种情况都满足时,会产生线程泄漏:

  • 子线程执行的函数中没有显式的销毁子线程 (未执行 pthread_detach()
  • 主线程中也没有等待子线程的结束 (未执行 pthread_join()

3. pthread 线程泄漏例子

3.1 代码

这里简单起见, 线程函数 f() 采用极简方式设定:传空指针参数, 只打印一句话和返回空指针。

// 这是一个反面例子。#include <cstddef>
#include <pthread.h>
#include <stdio.h>void* f(void*)
{printf("Hello from thread function f\n");return NULL;
}int main()
{pthread_t t;pthread_create(&t, NULL, f, NULL); // 主线程里开启子线程 tprintf("This is main thread\n");return 0;
}

3.2 编译和运行

zz@Legion-R7000P% clang++ leak_example.cpp

第一次运行

zz@Legion-R7000P% ./a.out 
Hello from thread function f
This is main thread

第二次运行

zz@Legion-R7000P% ./a.out
This is main thread

3.3 简要分析

由于主线程(main()函数)没有等待子线程的结束, 程序运行可能出现的情况有两种:

  • 打印了子线程的内容
  • 没打印子线程的内容

以上两种结果都可能出现, 不能认为能出现正确结果就万事大吉了, 需要严格确保结果的正确性。

4. 检测线程泄漏

使用 ThreadSanitizer 可以检查 Pthread 的内存泄漏。需要的步骤如下

4.1 编译链接时传入参数 -fsanitize=thread

clang++ leak_example.cpp -fsanitize=thread

4.2 确认 TSAN_OPTIONS 环境变量

第一种: TSAN_OPTIONS 环境变量为空。
第二种: 设定为检测线程泄漏: export TSAN_OPTIONS="report_thread_leaks=1"

以上两种情况,都可以让线程泄漏的问题在程序运行阶段被报告出来。
而如果设定了 export TSAN_OPTIONS="report_thread_leaks=0", 则无法报告线程泄漏问题。

5. 修复线程泄漏

5.1 方法1: 主线程等待子线程

#include <cstddef>
#include <pthread.h>
#include <stdio.h>void* f(void*)
{printf("Hello from thread function f\n");return NULL;
}int main()
{pthread_t t;pthread_create(&t, NULL, f, NULL); // 主线程里开启子线程 tpthread_join(t, NULL); // 主线程等待子线程 t 的结束return 0;
}

5.2 方法2:子线程主动脱离主线程

用到了 pthread_detach() 这个 API:

在这里插入图片描述
应用到代码中:

#include <cstddef>
#include <pthread.h>
#include <stdio.h>void* f(void*)
{pthread_detach(pthread_self()); // 子线程主动 detachprintf("Hello from thread function f\n");return NULL;
}int main()
{pthread_t t;pthread_create(&t, NULL, f, NULL); // 主线程里开启子线程 treturn 0;
}

http://www.ppmy.cn/news/77103.html

相关文章

SSRF-服务器端请求伪造

漏洞定义和成因 SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。 一般情况下&#xff0c;SSRF攻击的目标是从外网无法访问的内部系统。&#xff08;正是因为它是由服务端发起的&#xff0c;所以它能够请求到与它…

6. python的for循环

文章目录 一、for循环1.1、for循环分析1.2、注意事项 二、遍历数值列表2.1、range()函数的使用2.2、 创建数值列表2.3、对数值列表进行简单统计 一、for循环 有时&#xff0c;我们需要对列表内的所有元素逐一进行相同的操作&#xff0c;为避免出现大量重复的代码&#xff0c;p…

day9 - 对花朵图像进行边缘检测

本期主要介绍常用于进行图像边缘检测的滤波器&#xff08;算子&#xff09;&#xff1a;Sobel算子、Scharr算子、Laplacian算子&#xff1b;通过实验比较不同的算子的处理效果以及使用场景。 完成本期内容&#xff0c;你可以&#xff1a; 了解图像梯度的原理和应用 掌握使用S…

NTM中attr的用法

代码1 attrs class CopyTaskParams(object):name attrib(default"copy-task")controller_size attrib(default100, convertint)controller_layers attrib(default1,convertint)num_heads attrib(default1, convertint)sequence_width attrib(default8, convert…

技术大佬们都是怎么学习的?

目录 问题 熟悉更多业务 熟悉端到端 自学 Do exercise Learning trying Teaching 问题 今天逛帖子的时候&#xff0c;看到这么个问题&#xff1a; 这个问题我曾经也很好奇过&#xff0c;那些成为技术大佬的人当初是怎么学习&#xff0c;以及怎么成长过来的&#xff0…

Shellcode分离加载实现免杀的两种方式(VT免杀率:1/68)

简介 本文详细介绍了如何通过文件加载和远程URL加载方式实现Shellcode分离加载&#xff0c;以规避安全软件的检测。文章首先描述了通过Metasploit Framework生成的shellcode文件加载的过程&#xff0c;并提供了相关的C代码。 为了避免被杀毒软件检测&#xff0c;利用动态API调…

论文分享 A ConvNet for the 2020s

摘要 视觉识别的“咆哮的 20 年代”始于 Vision Transformers (ViTs) 的引入&#xff0c;它迅速取代了 ConvNets&#xff0c;成为最先进的图像分类模型。另一方面&#xff0c;vanilla ViT 在应用于对象检测和语义分割等一般计算机视觉任务时面临困难。正是层次化的 Transforme…

从零实现一个数据库(DataBase) Go语言实现版 4.B树实现(Part1))

英文源地址 本章将使用Go语言实现一个不可变地B树.这是一个最小实现, 因此很容易理解. Node节点的格式 我们的B树最终将被持久化到磁盘上, 因此我们首先需要为b树节点设计数据格式.如果没有这种格式, 我们将无法知道节点的大小以及何时拆分节点. 一个节点包含: 一个固定大小…