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

本文介绍了线程泄漏的概念,特别是在使用pthread库时如何产生线程泄漏。通过一个反面示例展示了线程泄漏的现象,并提供了使用ThreadSanitizer进行检测的方法。同时,文章提出了两种修复线程泄漏的策略:主线程等待子线程结束或者子线程主动脱离主线程。
摘要由CSDN通过智能技术生成


在这里插入图片描述

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); // 主线程里开启子线程 t
    printf("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); // 主线程里开启子线程 t

    pthread_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()); // 子线程主动 detach
    printf("Hello from thread function f\n");
    return NULL;
}

int main()
{
    pthread_t t;
    pthread_create(&t, NULL, f, NULL); // 主线程里开启子线程 t

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值