#include
#include
#include
#include
void* fun(void *arg){
sleep(30);
printf("%ld thread exit\n", syscall(SYS_gettid)); // syscall(SYS_gettid)返回轻量级进程LWP的id,相当于内核线程ID
pthread_exit(0);
}
int main(){
pthread_t tid;
int res = pthread_create(&tid, NULL, fun, NULL);
printf("main pid = %d\n", getpid());
sleep(20);
printf("main pthread_exit\n");
return 0; // 就是调用exit(0)
}
我们启动程序,看到该进程号为17428,我们使用watch -n 1 ps -Lf 17428每隔1s刷新一次该命令,查看17428的线程信息

我们看到main调用return后,两个线程一起退出了

#include
#include
#include
#include
void* fun(void *arg){
sleep(30);
printf("%ld thread exit\n", syscall(SYS_gettid)); // syscall(SYS_gettid)返回轻量级进程LWP的id
pthread_exit(0);
}
int main(){
pthread_t tid;
int res = pthread_create(&tid, NULL, fun, NULL);
printf("main pid = %d\n", getpid());
sleep(20);
printf("main pthread_exit\n");
pthread_exit(0);
// return 0; // 就是调用exit(0)
}
我们启动程序,看到该进程号为16266,我们使用watch -n 1 ps -Lf 16266每隔1s刷新一次该命令,查看16266的线程信息

当main线程调用pthread_exit后,就成为僵尸线程了,其实也是僵尸进程,linux下并没有真正意义上的线程存在,linux中使用进程来模拟实现线程,父进程创建子进程,子进程执行父进程的一部分代码,并且与父进程共享同一个地址空间。这些一个一个被创建出来的子进程可看做线程,这种线程也称之为轻量级进程。
main线程结束了,此时子线程还在正常运行。一般来说,不建议这么做,子线程退出后,主线程可以等待回收;但是子线程不会去回收主线程,所以主线程退出的时候,由于没有人回收,这个时候,主线程就会出现类似于“僵尸进程”的情况

子线程正常退出,线程全部退出,进程销毁

分析:
main函数的return,相当于是在线程中调用了系统函数exit,其他函数调用return不会触发exit(任何线程半路调用exit,都会导致进程终止),表示直接终止了整个进程,那么操作系统会把当前进程所有的资源,包括内存、io、线程、管道、fd等全部终止使用并且回收,相当于进程啥都没了
而 pthread_exit,仅仅只是结束当前线程,进程地址空间还在,所有的资源也都在,其他线程可以正常使用进程地址空间
普通thread在main线程结束前,一定要join thread,保证业务执行的完整性; detach thread不需要,一般detach thread设计的目的,就是在后台做一些非关键性任务,是否正常结束并没有要求,也不会出什么错误,如果要求任务的执行必须是完整的,不能设计成detach thread
#include
#include
#include
#include
#include
void* fun(void *arg){
sleep(20);
printf("%ld thread exit\n", syscall(SYS_gettid));
pthread_exit(0);
}
int main(){
pthread_t tid;
int res = pthread_create(&tid, NULL, fun, NULL);
printf("main pid = %d\n", getpid());
sleep(10);
pthread_join(tid, NULL); // 第二个参数是void*,用于接收线程函数的返回值
printf("main pthread_exit\n");
return 0; // 就是调用exit(0)
}
int pthread_detach(pthread_t tid); // 成功返回0,失败返回error number
pthread_detach后的线程结束后,其退出状态不由其他线程获取,而是由系统获取后释放资源,这种detach线程不会产生僵尸进程
pthread_detach()和pthread_join()就是控制子线程回收资源的两种不同的方式。同一进程间的线程具有共享和独立的资源,其中共享的资源有堆、全局变量、静态变量、文件等公用资源。而独享的资源有栈和寄存器,这两种方式就是决定子线程结束时如何回收独享的资源
如果是joinable状态,则该线程结束后(通过pthread_exit结束或者线程执行体任务执行完毕)不会释放线程所占用堆栈和线程描述符(总计8K多)等资源,除非在主线程调用了pthread_join函数之后才会释放(如果不调用pthread_join,那就只有进程终止时,才能回收线程资源了)。pthread_join函数一般应用在主线程需要等待子线程结束后才继续执行的场景,pthread_join是一个阻塞函数,调用方会阻塞到pthread_join所指定的tid的线程结束后才被回收。这跟子进程很相似,如果不用父进程wait回收的话,就会变成僵尸进程;同理,如果一个可结合态线程不用pthread_join回收,则会变成类似僵尸进程
如果是unjoinable状态,即detach后的线程,它的资源在它终止时由系统自动释放。实现方式是在创建时指定属性,或者在线程执行体的最开始处添加一行:pthread_detach(pthread_self());不会阻塞,调用它后,线程运行结束后会自动释放资源,后者非常方便
总结:
pthread_detach()即主线程与子线程分离,两者相互不干涉,但是分离线程还是使用所属进程的地址空间,如果主线程调用exit,会导致进程终止,所有的资源都被回收,分离线程也会被销毁。分离线程不能再join,否则报错
pthread_join()即是子线程合入主线程,主线程会一直阻塞,直到子线程执行结束,然后回收子线程资源,并继续执行