pthread 主线程子线程退出关系

本文探讨了主线程与新创建子线程之间的关系,包括主线程如何影响子线程的生命周期。通过不同场景的代码示例展示了主线程退出时,子线程可能的行为,揭示了POSIX线程API中关于线程退出的重要细节。

我们在一个线程中经常会创建另外的新线程,如果主线程退出,会不会影响它所创建的新线程呢?下面就来讨论一下。

1、 主线程等待新线程先结束退出,主线程后退出。正常执行。
实例代码:

#include "apue.h"  
#include <pthread.h>  

pthread_t ntid;//线程ID  

void printids(const char *s)  
{  
        pid_t pid;  
        pthread_t tid;  
        pid = getpid();  
        tid = pthread_self();  
        printf("%s pid %u tid %u (0x%x)\n",s,(unsigned int)pid,  
                        (unsigned int)tid,(unsigned int)tid);  
}  

void *thrfun(void *arg){  
        //sleep(1);//使得主线程先退出  
        printids("new thread");  

        return ((void *)0);  
}  

int main(){  
        int err;  
        err = pthread_create(&ntid,NULL,thrfun,NULL);  

        if(err != 0)  
                err_quit("can't create thread: %s\n",strerror(err));  
        printids("main thread");  

        sleep(1);//等待新线程先结束  

        exit(0);  
}  

运行结果:
这里写图片描述

2、 进程先退出,新线程也会立即退出,系统清除所有资源。
实例代码:

#include "apue.h"  
#include <pthread.h>  

pthread_t ntid;//线程ID  

void printids(const char *s)  
{  
        pid_t pid;  
        pthread_t tid;  
        pid = getpid();  
        tid = pthread_self();  
        printf("%s pid %u tid %u (0x%x)\n",s,(unsigned int)pid,  
                        (unsigned int)tid,(unsigned int)tid);  
}  

void *thrfun(void *arg){  
        sleep(1);//使得主线程先退出  
        printids("new thread");  

        return ((void *)0);  
}  

int main(){  
        int err;  
        err = pthread_create(&ntid,NULL,thrfun,NULL);  

        if(err != 0)  
                err_quit("can't create thread: %s\n",strerror(err));  
        printids("main thread");  

        //sleep(1);  

        exit(0);//注意是进程(不是线程)退出  
}  

运行结果:
这里写图片描述
可以发现主线程退出后所创建的新线程也停止运行了。

3、如果主线程调用了pthread_exit,那么它退出了,子线程也不会退出。
实例代码:

#include "apue.h"  
#include <pthread.h>  

pthread_t ntid;//线程ID  

void printids(const char *s)  
{  
        pid_t pid;  
        pthread_t tid;  
        pid = getpid();  
        tid = pthread_self();  
        printf("%s pid %u tid %u (0x%x)\n",s,(unsigned int)pid,  
                        (unsigned int)tid,(unsigned int)tid);  
}  

void *thrfun(void *arg){  
        sleep(1);//使得主线程先退出  
        printids("new thread");  

        return ((void *)0);  
}  

int main(){  
        int err;  
        err = pthread_create(&ntid,NULL,thrfun,NULL);  

        if(err != 0)  
                err_quit("can't create thread: %s\n",strerror(err));  
        printids("main thread");  

        //sleep(1);  

            pthread_exit(NULL);  

        exit(0);  
}  

运行结果:
这里写图片描述

POSIX标准定义:
When you program with POSIX Threads API,there is one thing about pthread_exit() that you may ignore for mistake. Insubroutines that complete normally, there is nothing special you have to dounless you want to pass a return code back using pthread_exit(). The completionwon’t affect the other threads which were created by the main thread of thissubroutine. However, in main(), when the code has been executed to the end,there could leave a choice for you. If you want to kill all the threads thatmain() created before, you can dispense with calling any functions. But if you want to keep the process and all the other threadsexcept for the main thread alive after the exit of main(), then you can call pthread_exit()to realize it. And any files opened inside the main thread will remain openafter its termination.

按照POSIX标准定义,当主线程在子线程终止之前调用pthread_exit()时,子线程是不会退出的。

注意:这里在main函数中调用pthread_exit()只会是主线程退出,而进程并未退出。因此新线程继续执行而没有退出。
我们可以在return 0;这条语句前面添加一条输出语句printf(“Mainthread has exited!\n”);来进行测试,输出结果不发生任何变化,说明这条语句没有被执行到。也就说明进程并未退出。

因此:
一个线程的退出不会影响另外一个线程。但是进程结束,所有线程也就结束了,所有资源会被回收。

我们可以再写一个程序来进行验证:
4、在创建的新线程B中再次创建新线程C,那么如果B先退出,那么C将会继续执行而不会退出。
实例代码:

#include "apue.h"  
#include<pthread.h>  

pthread_t ntid;//线程ID  

void printids(const char *s)  
{  
        pid_t pid;  
        pthread_t tid;  
        pid = getpid();  
        tid = pthread_self();  
        printf("%s pid %u tid %u (0x%x)\n",s,(unsigned int)pid,  
                       (unsigned int)tid,(unsigned int)tid);  
}  


void *thrfun2(void *arg){  
        sleep(1);//使得创建它的主线程先退出  
        printids("new thread of the new thread");  

        return ((void *)0);  
}  

void *thrfun(void *arg){  
        sleep(1);//使得主线程先退出  
        printids("new thread");  
        int err;  
        err = pthread_create(&ntid,NULL,thrfun2,NULL);  

        if(err != 0)  
                err_quit("can'tcreate thread: %s\n",strerror(err));  

        return ((void *)0);  
}  

int main(){  
        int err;  
        err = pthread_create(&ntid,NULL,thrfun,NULL);  

        if(err != 0)  
                err_quit("can'tcreate thread: %s\n",strerror(err));  
        printids("main thread");  

        //sleep(1);  

        pthread_exit(NULL);  

        printf("main thread has exited!\n");  

        exit(0);  
}  

运行结果:
这里写图片描述

<think>我们正在讨论pthread_create创建线程以及线程退出机制。根据引用内容,我们可以总结如下: 1. **线程创建**:使用`pthread_create`函数创建新线程。 2. **线程退出机制**:线程可以通过四种方式终止: - 调用`pthread_exit()`函数。 - 线程函数(`start_routine`)执行结束并返回。 - 被其他线程调用`pthread_cancel()`取消。 - 整个进程退出。 关于`pthread_create`函数,其原型为: ```c int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); ``` 参数说明: - `thread`:指向线程标识符的指针。 - `attr`:线程属性,通常为`NULL`表示默认属性。 - `start_routine`:线程函数的入口地址,该函数返回`void*`,参数为`void*`。 - `arg`:传递给线程函数的参数。 关于线程退出机制,详细说明如下: 1. **调用`pthread_exit()`**:线程可以显式调用`pthread_exit(void *retval)`来终止自己,并将`retval`作为退出状态。注意,`retval`不能指向线程栈上的局部变量,因为线程退出后栈空间会被回收。 2. **线程函数正常返回**:当线程的入口函数`start_routine`执行到`return`语句并返回一个值,该线程也会终止。返回的值同样可以通过`pthread_join`获取。 3. **被其他线程取消**:通过`pthread_cancel(pthread_t thread)`向目标线程发送取消请求。目标线程是否响应以及何时响应取决于其可撤销状态(`cancelability state`)类型(`cancelability type`): - 可撤销状态:`PTHREAD_CANCEL_ENABLE`(默认)表示响应取消请求;`PTHREAD_CANCEL_DISABLE`表示忽略取消请求。 - 可撤销类型:当状态为`ENABLE`时,类型决定取消的时机: - `PTHREAD_CANCEL_DEFERRED`(默认):延迟取消,直到线程到达取消点(一般是系统调用)。 - `PTHREAD_CANCEL_ASYNCHRONOUS`:异步取消,可能在任何时间点取消(不推荐,可能导致资源未释放)。 - 注意:如果目标线程不执行系统调用,可以使用`pthread_testcancel()`函数设置取消点,让线程有机会响应取消请求。 4. **进程退出**:如果整个进程退出(例如主线程调用`exit()`,或进程收到终止信号),则所有线程都会终止。 另外,线程退出后,如果该线程是`joinable`(可连接)的,则必须由其他线程调用`pthread_join`来回收其资源(如栈空间)并获取其退出状态。如果不进行`pthread_join`,则线程资源会泄漏(类似于进程中的僵尸进程)。 示例代码: ```c #include <pthread.h> #include <stdio.h> #include <unistd.h> // 线程函数 void* thread_func(void* arg) { printf("Thread started\n"); // 模拟工作 sleep(1); // 退出线程,返回状态 pthread_exit((void*)42); } int main() { pthread_t tid; // 创建线程 if (pthread_create(&tid, NULL, thread_func, NULL) != 0) { perror("pthread_create"); return 1; } void* retval; // 等待线程结束并获取退出状态 if (pthread_join(tid, &retval) != 0) { perror("pthread_join"); return 1; } printf("Thread exited with status: %ld\n", (long)retval); return 0; } ``` 在这个示例中,主线程创建了一个新线程,新线程执行`thread_func`函数,然后调用`pthread_exit`退出主线程通过`pthread_join`等待新线程结束并获取其退出状态。 注意事项: - 如果线程函数通过`return`返回,则返回值同样会被`pthread_join`捕获。 - 如果线程被取消,则`pthread_join`获取的退出状态是`PTHREAD_CANCELED`(一个特殊的值)。 §§相关问题§§ 1. 如何设置线程的属性(例如分离状态)? 2. `pthread_join``pthread_detach`有什么区别? 3. 线程取消的安全性问题(如何避免资源泄漏)? 4. 在多线程程序中,主线程退出时应该注意什么?</think>### pthread_create创建线程与线程退出机制 #### 1. 线程创建:`pthread_create` 函数原型: ```c int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg); ``` - **参数说明**: - `thread`:输出参数,返回新线程的ID - `attr`:线程属性(NULL表示默认属性) - `start_routine`:线程入口函数(返回`void*`,参数为`void*`) - `arg`:传递给线程函数的参数 - **返回值**:成功返回0,失败返回错误码 - **示例**: ```c #include <pthread.h> #include <stdio.h> void* thread_func(void* arg) { printf("Thread running. Argument: %s\n", (char*)arg); return NULL; } int main() { pthread_t tid; char* msg = "Hello Thread"; // 创建线程 if (pthread_create(&tid, NULL, thread_func, msg) != 0) { perror("Thread creation failed"); return 1; } pthread_join(tid, NULL); // 等待线程结束 return 0; } ``` #### 2. 线程退出机制 根据POSIX标准,线程终止有四种方式[^1]: 1. **显式调用`pthread_exit()`** ```c void pthread_exit(void *retval); ``` - 立即终止当前线程 - `retval`作为退出状态(不能指向局部变量) - 示例: ```c void* worker(void* arg) { if (error_occurred) pthread_exit((void*)-1); // 异常退出 return (void*)0; // 正常退出 } ``` 2. **线程函数正常返回** - 入口函数执行`return`语句时自动终止 - 返回值通过`pthread_join()`获取 3. **被其他线程取消** ```c int pthread_cancel(pthread_t thread); ``` - 需要目标线程配合: - **可撤销状态**:`PTHREAD_CANCEL_ENABLE`(默认)或`PTHREAD_CANCEL_DISABLE` - **可撤销类型**: - `PTHREAD_CANCEL_DEFERRED`(默认):在取消点(如系统调用)退出 - `PTHREAD_CANCEL_ASYNCHRONOUS`:立即退出(危险) - 强制产生取消点: ```c pthread_testcancel(); // 手动设置取消点[^3] ``` 4. **进程终止** - 进程调用`exit()`或收到终止信号时,所有线程立即终止 #### 3. 线程资源回收 - **可连接线程(Joinable)**: ```c int pthread_join(pthread_t thread, void **retval); ``` - 阻塞等待线程终止 - 获取退出状态(`pthread_exit`或`return`的值) - 必须调用以避免资源泄漏 - **分离线程(Detached)**: ```c pthread_detach(pthread_self()); // 线程内自行分离 ``` - 线程终止时自动回收资源 - 不可再调用`pthread_join` #### 4. 完整生命周期示例 ```c #include <pthread.h> #include <stdio.h> void* worker(void* arg) { printf("Worker started\n"); // 检查是否被取消 pthread_testcancel(); // 取消点[^4] // 线程工作逻辑... pthread_exit((void*)42); // 显式退出 } int main() { pthread_t tid; pthread_create(&tid, NULL, worker, NULL); // 主线程取消工作线程 pthread_cancel(tid); // 等待并获取退出状态 void* retval; pthread_join(tid, &retval); if (retval == PTHREAD_CANCELED) printf("Thread was canceled\n"); else printf("Exit code: %ld\n", (long)retval); return 0; } ``` #### 关键注意事项 1. 退出状态指针必须指向全局或堆内存,栈内存会失效[^1] 2. 默认创建的线程是joinable,必须调用`pthread_join`或`pthread_detach` 3. 取消线程需要目标线程到达取消点(系统调用或`pthread_testcancel()`)[^2][^3] 4. 主线程退出会导致整个进程终止,所有线程立即结束
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值