关于线程的内存泄漏问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Peter_tang6/article/details/82014115
线程在程序设计中占有很重要的地位,而关于线程的使用方法和注意事项也有很多,这篇文章主要讲讲如何创建一个线程并且让我们的程序避免内存泄露问题的出现。

线程的创建很简单,使用pthread_create函数,但是要注意参数的问题。

下面就一些例子说明线程的内存泄露问题。

```
#include "../common.h"         //包含一些函数所需要的头文件

pthread_t  tid;

void *func1(void *argc)
{
    #if 1
    int i;
    int max = *(int *)argc;
    for (i = 0; i < max; i++)
    {
        printf("%d\n", i);
    }
    #endif
    //pthread_detach(pthread_self());                         //线程的分离,注释以后如果不使用pthread_join函数回收资源,则会出现内存泄露
    return "OK";
}

int mypthread_create(pthread_t *tid, const pthread_attr_t *attr,
                void*(* func)(void *), void *arg)
{
    int res;
    if ((res = pthread_create(tid, attr, func, arg)) == 0)
    {
        printf("pthread %lu create success!\n", pthread_self());
    }
    else
    {
        return -1;
    }

    return 0;
}

int mypthread_join(pthread_t tid, void **status)
{
    int res;
    if ((res = pthread_join(tid, (void *)&status)) == 0)
    {
        printf("%s\n", (char *)status);              //用于输出线程的返回值
    }
    else
    {
        printf("errno = %d\n", errno);
        return -1;
    }

    return 0;
}

int main(int argc, char **argv)
{
    int n = 5;
    void **str;

    int res = mypthread_create(&tid, NULL, (void *)func1, (void *)&n);
    if (res == -1)
        error("pthread create failed!");           //包裹的perror函数和exit函数

    //res = mypthread_join(tid, str);         //注释pthread_join函数,如果没有创建线程分离状态,则会导致内存泄露
    //if (res == -1)
    //  error("pthread_join");               
    sleep(10);               //在没有调用pthread_join的情况下睡眠足够时间让线程有足够的时间执行
    printf("hello\n");
    return 0;
}
```

这个程序虽然很基础,但是在实验的时候也遇上了许多问题

  1. pthread_create的第三个参数应该为一个创建线程以后要执行的函数,我开始为了测试写了一个NULL,然后导致创建线程以后出现段错误而退出程序,建议在主函数中等待足够时间,让线程执行,这样才会看到线程执行的一个状态和一些打印。
  2. 线程既然是我们创建的资源,那在程序结束之后应该将其释放,其中使用pthread_join函数以及创建分离线程是有效的解决办法。
  3. 关于线程如何退出,退出分为显性退出和隐性退出,所谓显性退出,就是在希望线程退出的地方调用pthread_exit函数,注意函数的参数必须为全局的,因为此参数为线程退出码的存址,如果为局部的,则pthread_join函数将获取不了线程的退出状态。隐性退出即让线程执行完以后自然退出。

这里主要说说第二个问题
pthread_join函数用于阻塞等待指定线程结束,并能获取终止线程的状态,但是更重要的是它能够清理回收线程的资源。而分离线程的意义即为在线程退出时不需要pthread_join就能完成资源的回收,当我们不关心线程的状态时,可以使用线程分离。下面是没有使用pthread_join和分离线程的程序的运行状态,通过valgrand工具可查看我们的程序是否有内存泄漏的情况,工具安装及使用在https://blog.csdn.net/Peter_tang6/article/details/76833843

这里写图片描述

其中红色标出来的即为内存泄漏的情况,可以看出是在pthread_create创建线程的时候引发的。

下图是加入之后的变化

这里写图片描述

那么如果我们同时加上pthread_join函数和线程分离会发生什么情况呢?

这里写图片描述

errno = 0,还返回success,说明没有错误,也就是说这里暂时还没发现问题。

还有一种回收资源的方法就是创建线程的分离属性,关于线程的属性有很多,这里先说一说分离属性,线程的分离属性在创建新子线程之前就可以设定,也可以像开始一样创建新线程之后用pthread_detach函数设定。下面是修改的部分代码

pthread_t  tid;
pthread_attr_t   attr;         //线程属性变量
int main(int argc, char **argv)
{
    int n = 5;
    void **str;
    int err;

    err = pthread_attr_init(&attr);        //初始化线程属性
    if (err != 0)
        error("pthread_attr_init");
    err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);   //创建新线程之前设置分离属性
    if (err == 0)
    {
        int res = mypthread_create(&tid, &attr, (void *)func1, (void *)&n);   //第二个参数改为线程属性
        if (res == -1)
        error("pthread create failed!");
    }
    sleep(10);

    #if 0
    res = mypthread_join(tid, str);
    if (res == -1)
        error("pthread_join");
    printf("hello\n");
    #endif

    pthread_attr_destroy(&attr);    //唯一可销毁线程属性的函数
    return 0;
}

线程的内存泄露问题在这里告一段落,以后有其它问题再更新。

猜你喜欢

转载自blog.csdn.net/Peter_tang6/article/details/82014115