4、线程终止
终止线程的三种方法:
从线程函数return
线程可以调用pthread_ exit终止自己
线程可以调用pthread_ cancel终止同一进程中的另一个线程或者自己
注:在主线程使用return,以及在线程中使用exit都会终止整个进程
pthread_exit函数原型:
void pthread_exit(void *value_ptr);
解释:
功能:线程终止
参数:value_ptr线程退出传出的数据(不要指向一个局部变量)
返回值:无返回值,跟进程一样,线程结束的时候无法返回到它自身
注:pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了
pthread_cancel函数原型:
int pthread_cancel(pthread_t thread);
解释:
功能:取消一个执行中的线程
参数:thread表示要操作的线程的ID
返回值:成功返回0;失败返回错误码
注:pthread_cancel函数具有一定的延时性,并不会立即被处理,不建议当线程立即被创建后立即进行cancel取消(线程创建,并不会立即被调度);也不建议在线程退出前执行线程cancel取消(线程可能在取消之前就已经退出了);建议在线程执行中进行cancel取消线程
示例:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> void *thread1(void *arg) { printf("%s returning ... \n",(char*)arg); int *p = (int*)malloc(sizeof(int)); *p = 1; return (void*)p; } void *thread2(void *arg) { printf("%s exiting ...\n",(char*)arg); int *p = (int*)malloc(sizeof(int)); *p = 2; pthread_exit((void*)p); } void *thread3(void *arg) { while ( 1 ){ // printf("%s is running ...\n",(char*)arg); sleep(1); } return NULL; } int main( void ) { pthread_t tid; void *ret; // thread 1 return pthread_create(&tid, NULL, thread1, (void*)"thread 1"); pthread_join(tid, &ret); printf("thread 1 return, thread id %X, return code:%d\n", tid, *(int*)ret); free(ret); // thread 2 exit pthread_create(&tid, NULL, thread2, (void*)"thread 2"); pthread_join(tid, &ret); printf("thread 2 exit, thread id %X, return code:%d\n", tid, *(int*)ret); free(ret); // thread 3 cancel by other pthread_create(&tid, NULL, thread3, (void*)"thread 3"); sleep(3); pthread_cancel(tid); pthread_join(tid, &ret); if (ret == PTHREAD_CANCELED) printf("thread 3 cancel, thread id %X, return code: PTHREAD_CANCELED->%d\n", tid,ret); else printf("thread return, thread id %X, return code:%d\n", tid,ret); return 0; }
5、线程等待
为什么需要线程等待:
已经退出的线程,其空间没有被释放,仍然在进程的地址空间内,创建新的线程不会复用刚才退出线程的地址空间,如果主线程不对新线程进行等待,那么这个新线程的资源也是不会被回收的。如果不等待会产生内存泄漏
线程是用来执行分配的任务的,如果主线程想知道任务完成的怎么样,那么就有必要对线程进行等待,获取线程退出的信息
pthread_join函数原型:
int pthread_join(pthread_t thread, void **value_ptr);
解释:
功能:等待线程结束
参数:thread:指定等待线程的ID;value_ptr:输出型参数,用来获取指向线程的返回值
返回值:成功返回0;失败返回错误码
注意:
调用该函数的线程将挂起等待,直到id为thread的线程终止
这里获取的线程退出信息并没有终止信号信息,而终止信号信息是对于整个进程来说的,如果线程收到信号崩溃也会导致整个进程也崩溃
thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的
终止获取的状态情况:
如果thread线程通过return返回,value_ ptr所指向的单元里存放的是thread线程函数的返回值
如果thread线程被别的线程调用pthread_ cancel异常终掉,value_ ptr所指向的单元里存放的是常数PTHREAD_ CANCELED
如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数
如果对thread线程的终止状态不感兴趣,可以传NULL给value_ ptr参数
示图:
示例:
#include<stdio.h> #include<unistd.h> #include<pthread.h> #include<stdlib.h> #include<string.h> int val=0; struct Ret { int exitno; int exittime; //... }; void* Routine(void* avgs) { int cnt=1; while(1) { printf("I am %s... val:%d\n",(char*)avgs,val); sleep(1); cnt++; if(cnt==3) { struct Ret* p=(struct Ret*)malloc(sizeof(struct Ret)); p->exitno=0; p->exittime=6666; pthread_exit((void*)p); //pthread_cancel(pthread_self()); } } } int main() { pthread_t tid1,tid2,tid3; pthread_create(&tid1,NULL,Routine,(void*)"pthread 1"); pthread_create(&tid2,NULL,Routine,(void*)"pthread 2"); pthread_create(&tid3,NULL,Routine,(void*)"pthread 3"); int cnt=0; while(1) { printf("I am main pthread...val:%d\n",val++); sleep(1); cnt++; if(cnt==3) break; } printf("wait for pthread...\n"); void* ret; pthread_join(tid1,&ret); printf("pthread id:%x exitno:%d exittime:%d\n",tid1,((struct Ret*)ret)->exitno,((struct Ret*)ret)->exittime); pthread_join(tid2,&ret); printf("pthread id:%x exitno:%d exittime:%d\n",tid2,((struct Ret*)ret)->exitno,((struct Ret*)ret)->exittime); pthread_join(tid3,&ret); printf("pthread id:%x exitno:%d exittime:%d\n",tid3,((struct Ret*)ret)->exitno,((struct Ret*)ret)->exittime); return 0; }
6、线程分离
- 概念:
默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏
如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源
pthread_detach函数原型:
int pthread_detach(pthread_t thread);
注意:
可以是线程组内其他线程对目标线程进行分离,也可以是线程自己分离: pthread_detach(pthread_self());
joinable和分离是冲突的,一个线程不能既是joinable又是分离的
线程的分离也是具有一定延时性,分离之后如果再进行等待那么得到返回的结果是未定义的
线程分离后只是回收的时候自动进行回收,如果主线程先退出,那么整个进程也会退出;如果分离的线程执行崩溃,同样的整个进行也会崩溃
示例:
#include <stdio.h> #include <pthread.h> #include <unistd.h> void* Routine (void* arg) { pthread_detach(pthread_self()); printf("%s detach success!\n"); int cnt=0; while(cnt<5) { cnt++; printf("%s running...\n",(char*)arg); sleep(1); } printf("%s return...\n"); return NULL; } int main() { pthread_t tid; pthread_create(&tid,NULL,Routine,(void*)"thread"); sleep(2);//等待线程分离 void* ret; if(pthread_join(tid,&ret)==0) printf("thread join success! ret:%d\n",(int*)ret); else printf("thread join fail... ret:%d\n",(int*)ret); return 0; }