3

linux使用pthread库多线程编程,即使设置pthread_detach,资源也残留部分,不完全释放...

 3 years ago
source link: https://blog.popkx.com/linux-uses-pthread-library-to-multithread-programming-even-if-pthread_detach-is-set-up-resources-will-remain/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

linux使用pthread库多线程编程,即使设置pthread_detach,资源也残留部分,不完全释放问题

发表于 2018-09-17 09:09:14   |   已被 访问: 708 次   |   分类于:   C语言 , Linux笔记   |   暂无评论
b5fb855ad1fa26dfc2108ee78ea8ca86.png

下面这段代码,是利用 pthread 库进行多线程编程的最简单的 demo 了:

#include "stdio.h"
#include "pthread.h"
//#include ...

void* testOcupMem(void* p)
{
    // pthread_detach(pthread_self());
    printf("                    %d testOcupMem exit\n", gettid());
    return NULL;
}

int main()
{
    int i = 15;
    pthread_t pid;

    while(i--){
        printf("---------------- %d\n", i);
        if(0>pthread_create(&pid, NULL, testOcupMem, &pid)){
           printf("---- create thread readVideo failed\n");
        }
        sleep(2);   
    }
    printf("\n------------- getchar --------------\n");
    getchar();
    return 0;
}

在 main 函数中,共创建 15 次线程,线程函数打印“testOcupMem exit”就退出。按理说,线程函数退出后,资源就被释放了,但是编译后执行,发现每次创建线程,内存占用都会增加。

于是 man 一下 pthread 函数,发现这么描述:

d444202d74540fd2fc4776333172eb5c.png

里面说到,线程分为 joinabledetached。只有两种情况,资源才会在线程结束时释放:
  • 如果线程是 joinable,则需要调用 pthread_join
  • 如果线程是 detached,则资源会随着线程函数结束,自动释放

这就视情况而定了,因为如果主线程使用 pthread_join,主线程会阻塞,难以做到和子线程共同工作。所以,这里将线程函数设置为 detached。方法很简单,就是调用 pthread_detach 函数。将上面 demo 线程函数中的 pthread_detach 函数解注释,再编译执行,发现程序使用内存不再随着创建线程次数增加了。

我们在主线程创建子线程之前,加入 getchar() 使主线程暂停。

...
int main()
{
    int i = 15;
    pthread_t pid;

    getchar();

    while(i--){
        ...

再编译执行,发现在创建子线程之前,程序占用内存仅为 1288

接着,按下回车,主线程开始创建子线程,发现创建子线程后,内存增加到 9484

**虽然程序多次创建子线程,使用内存不再继续增加,但是子线程全部退出后,程序仍然占用内存仍然为 9484**,这部分资源并没有释放,多出了 8196。

继续 man phread_detach函数:

35a88f29e4c0c55802085b160ade06c0.png

提到,线程资源在程序退出的时候才全部释放。

查看系统设置的堆栈大小:

# ulimit -s
8192

因此猜测:主线程创建子线程时使用的堆栈没有释放,仍然残留在主线程里。于是查阅 pthread_create 原理,发现它调用了 clone 函数。下面的 demo 模拟了 pthread_create 函数:

#define _GNU_SOURCE
#include "stdio.h"
#include "pthread.h"
#include "sched.h"
void* testOcupMem(void* p)
{
    printf("                    %d testOcupMem exit\n", gettid());
    return NULL;
}
#define STACK_SIZE 8192*1024
int main()
{
    int i = 15;

    void* pstk = malloc(STACK_SIZE);
    if(NULL == pstk){
         printf("query failed, cannot malloc stack\n");
         return -1;
    }
    while(i--){
        printf("---------------- %d\n", i);
        int clonePid = clone((int(*)(void*))testOcupMem,  (char *)pstk + STACK_SIZE,
                     CLONE_VM | CLONE_FS  | CLONE_FILES | SIGCHLD, pstk);
        printf("  clonePid: %d\n", clonePid);
        if(-1 ==  clonePid){    
            printf("query failed, cannot start query process\n");
            free(pstk);
            return -1;
        }
        sleep(2);   
    }
    free(pstk);         // pthread_create 创建线程时,堆栈没有释放
    printf("\n------------- getchar --------------\n");
    getchar();
    return 0;
}

模拟的最后部分,将堆栈释放掉,发现被一直子线程被创建前后,多占用的 8000 多内存空间被释放了。

所以,如果很在意这部分堆栈空间,可以用 clone 自己封装一个简易版的 pthread_create 函数。

阅读更多:   C语言 , Linux笔记


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK