线程分离

简介:

未分离线程

在我们使用默认属性创建一个线程的时候,线程是 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]\n");
            }
            sleep(2);
            try ++;
        }
    }
    printf("create [%d] threads\n", 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]\n");
            }
            sleep(2);
            try ++;
        }
    }
    printf("create [%d] threads\n", 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]\n");
            }
            sleep(2);
            try ++;
        }
        void *st = NULL;
        //这里等待一个线程的结束,并回收其资源
        err = pthread_join(pt, &st);
        if(0 != err) {
            printf("errno = [%d]\n", err);
            sleep(2);
            try ++;
        }
    }
    printf("create [%d] threads\n", 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() 还会得到线程退出后的返回值,来判断线程的退出状态 。



本文转自郝峰波博客园博客,原文链接:http://www.cnblogs.com/fengbohello/p/7583729.html,如需转载请自行联系原作者

相关文章
|
5月前
|
Linux API
Linux线程总结---线程的创建、退出、取消、回收、分离属性
Linux线程总结---线程的创建、退出、取消、回收、分离属性
|
6月前
|
存储 安全 Linux
【探索Linux】P.19(多线程 | 线程的概念 | 线程控制 | 分离线程)
【探索Linux】P.19(多线程 | 线程的概念 | 线程控制 | 分离线程)
48 0
|
6月前
|
存储 安全 Java
【亮剑】`ConcurrentHashMap`是Java中线程安全的哈希表,采用锁定分离技术提高并发性能
【4月更文挑战第30天】`ConcurrentHashMap`是Java中线程安全的哈希表,采用锁定分离技术提高并发性能。数据被分割成多个Segment,每个拥有独立锁,允许多线程并发访问不同Segment。当写操作发生时,计算键的哈希值定位Segment并获取其锁;读操作通常无需锁定。内部会根据负载动态调整Segment,减少锁竞争。虽然使用不公平锁,但Java 8及以上版本提供了公平锁选项。理解其工作原理对开发高性能并发应用至关重要。
53 0
|
存储 Linux 调度
【Linux】线程分离 | 线程库 | C++调用线程 | 线程局部存储
【Linux】线程分离 | 线程库 | C++调用线程 | 线程局部存储
142 0
|
物联网 Linux 开发者
Pthred_detach 线程分离|学习笔记
快速学习 Pthred_detach 线程分离
Pthred_detach 线程分离|学习笔记
线程的分离
线程的分离
149 0
|
存储 Linux 调度
Linux多线程:线程概念、线程间的独有与共享、多线程VS多进程,线程控制:线程创建、线程终止、线程等待、线程分离
Linux多线程:线程概念、线程间的独有与共享、多线程VS多进程,线程控制:线程创建、线程终止、线程等待、线程分离
230 0
|
Linux
Linux系统编程-(pthread)线程的使用案例(分离属性、清理函数等)
这篇文章介绍Linux下线程的创建与基本使用案例,主要是案例代码为主;相关的函数详细介绍在上篇文章里已经介绍过了。
209 0
|
Linux 调度 Android开发
【C++ 语言】线程 ( 线程创建方法 | 线程标识符 | 线程属性 | 线程属性初始化 | 线程属性销毁 | 分离线程 | 线程调度策略 | 线程优先级 | 线程等待 )(二)
【C++ 语言】线程 ( 线程创建方法 | 线程标识符 | 线程属性 | 线程属性初始化 | 线程属性销毁 | 分离线程 | 线程调度策略 | 线程优先级 | 线程等待 )(二)
324 0
|
调度 C++
【C++ 语言】线程 ( 线程创建方法 | 线程标识符 | 线程属性 | 线程属性初始化 | 线程属性销毁 | 分离线程 | 线程调度策略 | 线程优先级 | 线程等待 )(一)
【C++ 语言】线程 ( 线程创建方法 | 线程标识符 | 线程属性 | 线程属性初始化 | 线程属性销毁 | 分离线程 | 线程调度策略 | 线程优先级 | 线程等待 )(一)
256 0

相关实验场景

更多