zoukankan      html  css  js  c++  java
  • 线程分离

    未分离线程

    在我们使用默认属性创建一个线程的时候,线程是 joinable 的。 joinable 状态的线程,必须在另一个线程中使用 pthread_join() 等待其结束, 如果一个 joinable 的线程在结束后,没有使用 pthread_join() 进行操作, 这个线程就会变成"僵尸线程"。每个僵尸线程都会消耗一些系统资源, 当有太多的僵尸线程的时候,可能会导致创建线程失败。

    下面是一个创建僵尸线程的例子:

    void* start_thread(void * arg) {
        //这个线程什么也不做,直接退出
        pthread_exit(NULL);
        return NULL;
    }
    
    int create_pthread(int n) {
        int try = 0;
        int i = 0;
        int err = 0;
        for(i = 0; i < n && try < 3; i++) {
            //当创建线程失败的时候,尝试3次
            pthread_t pt;
            err = pthread_create(&pt, NULL, start_thread, NULL);
            if(0 != err) {
                if(EAGAIN == err) {
                    printf("errno : [EAGAIN]
    ");
                }
                sleep(2);
                try ++;
            }
        }
        printf("create [%d] threads
    ", i);
    
        return err;
    }
    
    int main(int argc, char * argv[]) {
        int n = 1 << 20;//最多创建 1M 个线程
        create_pthread(n);
    
        return 0;
    }

    上面代码是创建僵尸线程的主要部分,把上面代码编译执行后, 输出的结果是什么呢:

    errno : [EAGAIN]
    errno : [EAGAIN]
    errno : [EAGAIN]
    create [32754] threads

    在上面的例子中,每个线程开始后,什么也不做,立刻就结束。 最后在我的环境下,只能创建 32754 个额外线程。

    分离线程

    当线程被设置为分离状态后,线程结束时,它的资源会被系统自动的回收, 而不再需要在其它线程中对其进行 pthread_join() 操作。

    下面我们对代码做一些修改,让每个线程在开始执行后,进行线程的分离, 然后看看执行后的结果。

    void* start_thread(void * arg) {
        //注意,这里执行了线程的分离操作。线程分离也可以在线程创建的时候,
        //在属性里面设置
        pthread_detach(pthread_self());
    
        pthread_exit(NULL);
        return NULL;
    }
    
    int create_pthread(int n) {
        int try = 0;
        int i = 0;
        int err = 0;
        for(i = 0; i < n && try < 3; i++) {
            pthread_t pt;
            err = pthread_create(&pt, NULL, start_thread, NULL);
            if(0 != err) {
                if(EAGAIN == err) {
                    printf("errno : [EAGAIN]
    ");
                }
                sleep(2);
                try ++;
            }
        }
        printf("create [%d] threads
    ", i);
    
        return err;
    }
    
    int main(int argc, char * argv[]) {
        int n = 1 << 20;
        create_pthread(n);
    
        return 0;
    }

    执行结果如下:

    create [1048576] threads

    可以看到,最后成功创建了 1M 个线程。而没有进行 pthread_join() 操作的时候,最多创建创建了 32754 个线程,原因就是没有 detach 的线程,在其结束后,一些系统分配给它的资源还在被占用, 没有被回收,导致无法再创建新的线程了。而 detach 的线程,在其结束后, 它的资源会被系统进行回收,然后进行再利用。所以这次才能创建 1M 的线程。

    join 后的线程

    在 man pthread_create 手册中,可以看到关于一个线程的 detachd 状态和 joinable 状态的描述。其中说到,一个线程或者是 detachd 的状态,这样它结束后,资源会被系统 回收;或者是 joinable 状态,并且在另一个线程里面被 pthread_join() 等待,pthread_join() 会回收它的资源。

    我们可以再做个实验,在创建完了一个 joinable 的线程后再使用 pthread_join() 等待它的结束, 回收它的资源,看看最多可以创建多少个线程。

    void* start_thread(void * arg) {
    
        pthread_exit(NULL);
        return NULL;
    }
    
    int create_pthread(int n) {
        int try = 0;
        int i = 0;
        int err = 0;
        for(i = 0; i < n && try < 3; i++) {
            pthread_t pt;
            err = pthread_create(&pt, NULL, start_thread, NULL);
            if(0 != err) {
                if(EAGAIN == err) {
                    printf("errno : [EAGAIN]
    ");
                }
                sleep(2);
                try ++;
            }
            void *st = NULL;
            //这里等待一个线程的结束,并回收其资源
            err = pthread_join(pt, &st);
            if(0 != err) {
                printf("errno = [%d]
    ", err);
                sleep(2);
                try ++;
            }
        }
        printf("create [%d] threads
    ", i);
    
        return err;
    }
    
    int main(int argc, char * argv[]) {
        int n = 1 << 20;
        create_pthread(n);
    
        return 0;
    }

    执行结果:

    create [1048576] threads

    最后也是创建了 1M 个线程。

    结论就是,在我们编写多线程应用的时候,或者把一个线程的属性设置为 detachd 的状态,让系统来回收它的资源;或者是 joinable 状态,这样就可以使用 pthread_join() 来阻塞的等待一个线程的结束,并回收其资源,并且pthread_join() 还会得到线程退出后的返回值,来判断线程的退出状态 。

    同步地址:https://www.fengbohello.top/archives/linux-pthread-detach

  • 相关阅读:
    IDEA中用jetty启动项目时,url 404
    Mysql 性能查询
    RabbitMQ 安装
    Ubuntu安装kubernetes
    .net 4 调用WCF时报错 Type 'System.Threading.Tasks.Task`1[]' cannot be serialized
    Windows XP SP2上安装.net 4
    angular学习的一些Mark
    [转]对 td 使用 overflow:hidden; 无效的几点错误认识
    静态方法与非静态方法的区别
    二进制字符串的权限管理
  • 原文地址:https://www.cnblogs.com/fengbohello/p/7583729.html
Copyright © 2011-2022 走看看