一、线程终止
线程终止有三种方式,包括:
1.从线程函数return(对主线程不可使用),从main函数return相当于调用exit。
2.线程可以调用pthread_exit终止自己。
3.一个线程可以调用pthread_cancel终止同一进程中的另外一个线程。
我们来认识几个函数:
pthread_exit函数
用来终止进程,参数是void*类型,无返回值。
注意:return和pthread_exit返回的指针所指向的内存单元必须是全局的或者是malloc分配的,因为线程栈是私有的,当其他线程的得到这个函数的时候,该线程已经退出。
pthread_cancel函数
用来取消一个执行中的进程,成功返回0,失败返回错误码。
线程取消返回PTHREAD_CANCELED,是一个宏。
这个宏具体是什么呢?我们查找后发现是将-1转化为(void*)类型返回。
线程退出只有两种情况;
1.代码跑完,结果正确;
2.代码跑完,结果错误。
注意:和进程不同的是线程退出不包括线程异常退出,不会因为一个线程异常等待,只要有一个线程异常,主线程直接挂,不会等待。
二、线程等待
为什么需要线程等待?
在学习进程时,我们说过父进程通过wait函数或waitpid函数等待子进程,回收子进程的资源,获取子进程的退出信息,如果父进程没有等待,则会造成僵尸进程,子进程的描述符仍然保存在系统中。
线程也是一样的,如果不等待,则会造成类似僵尸线程的状况。已经退出的线程,其空间没有被释放,仍然在进程的地址空间内,创建的新线程不会复用刚才退出线程的地址空间。
代码实现:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
//return
void *func1(void *arg){
int *p = (int*)malloc(sizeof(int));
*p = 2;
return (void*)p;
}
//pthread_exit
void *func2(void *arg){
int *p = (int*)malloc(sizeof(int));
*p = 2;
pthread_exit((void*)p);
}
void *func3(void *arg){
while(1){
printf("thread 3 is running...\n");
sleep(1);
}
return NULL;
}
int main()
{
pthread_t tid;
void *ret;
//thread 1 return
pthread_create(&tid, NULL, func1, NULL);
pthread_join(tid, &ret);
printf("thread return, thread id %lu,return code:%d\n", tid, *(int*)ret);
free(ret);
//thread 2 exit
pthread_create(&tid, NULL, func2, NULL);
pthread_join(tid, &ret);
printf("thread return, thread id %lu,return code:%d\n", tid, *(int*)ret);
free(ret);
//thread 3 cancel by other
pthread_create(&tid, NULL, func3, NULL);
sleep(2);
pthread_cancel(tid);
pthread_join(tid, &ret);
if(ret == PTHREAD_CANCELED){
printf("thread return, thread id %lu,return code: PTHREAD_CANCELED\n", tid);
}else{
printf("thread return, thread id %lu,return code:NULL", tid);
}
while(1)
{
printf("I am main thread\n");
sleep(1);
}
return 0;
}
三、线程分离
1.线程的状态分为两种:可结合的(joinable)和分离的(detached),其中默认情况下新创建的线程是可结合的。
2.线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄露。若将线程分离,则该线程是不需要join的(即不能被其他线程回收其资源和杀死),运行完毕后,系统会自动回收。
3.线程分离可以是主线程将其分离,也可以是线程自己将自己分离。
4.若分离的线程异常,进程也会终止。因为线程分离是指资源层面上的分离,分离特性仅仅基于不出问题的情况。
我们来认识几个函数:
pthread_detach函数
用于分离一个线程,分离成功返回0,分离失败返回错误码。
代码实现线程分离
由结果可知,将创建的线程分离出去后,就不需要join了。
也可以创建出多个线程,用其他线程对该线程进程分离。如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void *func1(void *arg)
{
pthread_exit((void*)0);
}
void *func2(void *arg)
{
pthread_exit((void*)0);
}
int main()
{
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, func1, NULL);
pthread_create(&tid2, NULL, func2, NULL);
pthread_detach(tid1);
if(pthread_join(tid1, NULL) == 0){
printf("thread1 wait sucess\n");
}else{
printf("thread1 wait failed\n");
}
if(pthread_join(tid2, NULL) == 0){
printf("thread2 wait sucess\n");
}else{
printf("thread2 wait failed\n");
}
return 0;
}
分离线程可以自己将自己分离,也可以其他线程对目标线程进行分离。分离后的线程不需要主线程等待,运行完后系统会对其进程回收。而可结合的线程需要主线程进程等待,对该进程进行资源释放。