Linux下主线程和子线程的终止次序
之前在完成一个任务时需要实现主线程和子线程分别处理自己的任务,为了验证子线程的功能正常,需要让主线程在子线程之前结束,同时进程仍在运行。为了实现这种情况,特地了解主线程和子线程终止次序的相关之前。
前提知识
- 主线程和子线程之间没有必然的退出次序关系。主线程退出,子线程可以继续执行;子线程退出,主线程也可以继续执行。
- 程序加载到内存中执行的时候,进程就会生成一个主线程。虽然主线程和子线程之间没有必然的退出次序关系,但是如果进程终止,那么进程下所有的线程都会终止。
1、子线程先终止,主线程后终止
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
void *func(void *arg) {
printf("descendant thread");
pthread_detach(pthread_self());
return ((void*)0);
}
int main(void) {
pthread_t myid;
pthread_create(&myid, NULL, func, NULL);
sleep(1); // 等待子线程先退出
printf("main thread");
return 0;
}
//结果:先打印descendant thread,后打印main thread。
2、进程结束,所有线程都终止
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
void *func(void *arg) {
sleep(1);//等待主线程先退出
printf("descendant thread");
pthread_detach(pthread_self());
return ((void*)0);
}
int main(void) {
pthread_t myid;
pthread_create(&myid, NULL, func, NULL);
printf("main thread");
return 0;
}
//结果:此时会只打印main thread,然后进程结束。由于进程退出,该进程中的所有线程都会终止,系统回收所有的资源,因此子线程还没来得打印就已经退出了。
3、主线程先终止,子线程后终止
- 主线程需要调用 pthread_exit() 终止。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
void *func(void *arg) {
sleep(1);//等待主线程先退出
printf("descendant thread");
pthread_detach(pthread_self());
return ((void*)0);
}
int main(void) {
pthread_t myid;
pthread_create(&myid, NULL, func, NULL);
printf("main thread");
pthread_exit(NULL);
return 0;
}
//结果:主进程打印main thread后退出,子进程并没有退出,打印descendant thread后退出。最后进程退出,该进程中的所有线程都会终止,系统回收所有的资源。
总结
- 若想主线程在子线程前结束,并且进程不结束,就需要用到pthread_exit()函数。按照POSIX标准定义,当主线程在子线程终止之前调用pthread_exit()时,子线程是不会退出的。
- 这里在main函数中调用pthread_exit()只会是主线程退出,而进程并未退出。通过调用pthread_exit函数,线程会显式终止。如果主线程调用pthread_exit,它会先终止,然后等待其他子线程终止后,进程才终止。
- 函数pthread_exit()
- 函数原型:void pthread_exit( void * value_ptr );
- 线程的终止可以是调用了pthread_exit或者该线程的例程结束。也就是说,一个线程可以隐式的退出,也可以显式的调用pthread_exit函数来退出。
- pthread_exit函数唯一的参数value_ptr是函数的返回代码,只要pthread_join中的第二个参数value_ptr不是NULL,这个值将被传递给value_ptr。