在进程中,若调用了函数 exit,_exit,或_Exit 时,则该进程会终止,同样,若进程中的线程调用这三个函数时也会使线程所在的进程终止。那么要是只是退出线程,而不终止线程所在的进程有什么办法?下面是在单线程模式下退出线程的三种方式(不会终止线程所在的进程):
/* 线程终止 */ /* * 函数功能:退出线程; * 无返回值; * 函数原型: */ #include <pthread.h> void pthread_exit(void *rval_ptr); /* * 说明: * rval_ptr是一个无类型指针,与传给启动例程的单个参数类似; * 进程中的其他线程可以通过调用pthread_join函数访问到这个指针; */ /* * 函数功能:获取其他已终止的线程的退出码; * 返回值:若成功则返回0,否则返回错误编码; * 函数原型: */ int pthread_join(pthread_t thread, void **rval_ptr); /* * 说明: * 调用pthread_join的线程将一直阻塞,直到thread指定的线程调用pthread_exit、从启动例程返回或被取消; * 如果线程只是从启动例程返回,rval_ptr将包含返回码; * 如果线程是被取消,由rval_ptr指向的内存单元设置为PTHREAD_CANCELED; */通常父进程需要调用 wait 函数族等待子进程,避免子进程成为僵尸进程。在线程中为确保终止线程的资源对进程可用,即回收终止线程的资源,应该在每个线程结束时分离它们。一个没有被分离的线程终止时会保留其虚拟内存,包括它们的堆栈和其他系统资源。分离线程意味着通知系统不再需要此线程,允许系统将分配给它的资源回收。
#include "apue.h" #include <pthread.h> static void *func1(void *arg); static void *func2(void *arg); int main(void) { pthread_t tid1, tid2; int err; void *tret; err = pthread_create(&tid1, NULL, func1, NULL); if(err != 0) err_quit("can't create thread 1: %s\n", strerror(err)); err = pthread_create(&tid2, NULL, func2, NULL); if(err != 0) err_quit("can't create thread 2: %s\n", strerror(err)); err = pthread_join(tid1,&tret); if(err != 0) err_quit("can't join with thread 1: %s\n", strerror(err)); printf("thread 1 exit code %d\n", (int)tret); err = pthread_join(tid2,&tret); if(err != 0) err_quit("can't join with thread 2: %s\n", strerror(err)); printf("thread 2 exit code %d\n", (int)tret); exit(0); } static void *func1(void *arg) { printf("thread 1 returning\n"); return((void *)1); } static void *func2(void *arg) { printf("thread 2 exiting\n"); pthread_exit((void*)2); }
thread 1 returning thread 2 exiting thread 1 exit code 1 thread 2 exit code 2
/* * 函数功能:请求取消同一进程的其他线程; * 返回值:若成功则返回0,否则返回错误; * 函数原型: */ int pthread_cancel(pthread_t tid); /* * 说明: * 在默认情况下,该函数会使得由tid标识的线程的行为表现为如同调用了参数为PTHREAD_CANCELED的pthread_exit函数, * 但是线程可以选择忽略取消方式或控制取消方式; * 注意:pthread_cancel并不等待线程终止,它仅仅提出请求; */
/* * 函数功能:线程清理处理程序; * 无返回值; * 函数原型: */ void pthread_cleanup_push(void(*rtn)(void *), void *arg); void pthread_cleanup_pop(int execute); /* * 说明: * 当线程执行以下动作时调用清理函数,调用参数为arg: * (1)调用pthread_exit函数时; * (2)响应取消请求时; * (3)用非零execute参数调用pthread_cleanup_pop时; * 如果参数execute设置为0,清理程序函数不被调用; */测试程序:
#include <pthread.h> #include <sys/types.h> #include "apue.h" static void cleanup(void *arg); //线程清理函数 void *func1(void *arg); void *func2(void *arg); int main(void) { pthread_t tid1; pthread_t tid2; int err; void *tret; err = pthread_create(&tid1, NULL, func1, (void*)1); if(err != 0) err_quit("can't create thread 1: %s\n", strerror(err)); err = pthread_create(&tid2, NULL, func2, (void*)1); if(err != 0) err_quit("can't create thread 2: %s\n", strerror(err)); err = pthread_join(tid1,&tret); if(err != 0) err_quit("can't join with thread 1: %s\n", strerror(err)); printf("thread 1 exit code %d\n", (int)tret); err = pthread_join(tid2, &tret); if(err != 0) err_quit("can't join with thread 2: %s\n", strerror(err)); printf("thread 2 exit code %d\n",(int)tret); exit(0); } static void cleanup(void *arg) { printf("cleanup: %s\n", (char*)arg); } void *func1(void *arg) { printf("thread 1 start.\n"); pthread_cleanup_push(cleanup,"thread 1 first handler"); pthread_cleanup_push(cleanup,"thread 1 second handler"); printf("thread 1 push complete.\n"); if(arg) return ((void*)1); //返回终止,将不会调用清理处理程序 pthread_cleanup_pop(0); pthread_cleanup_pop(0); return ((void*)1); } void *func2(void *arg) { printf("thread 2 start.\n"); pthread_cleanup_push(cleanup,"thread 2 first handler"); pthread_cleanup_push(cleanup,"thread 2 second handler"); printf("thread 2 push complete.\n"); if(arg) pthread_exit((void*)2); //会调用清理处理程序 pthread_cleanup_pop(0); pthread_cleanup_pop(0); pthread_exit((void*)2); }输出结果:
thread 1 start. thread 2 start. thread 2 push complete. cleanup: thread 2 second handler cleanup: thread 2 first handler thread 1 push complete. thread 1 exit code 1 thread 2 exit code 2
/* * 函数功能:使线程处于分离状态; * 返回值:若成功则返回0,否则返回错误编码; * 函数原型: */ int pthread_detach(pthread_t tid);测试程序:
#include <pthread.h> #include "apue.h" void *thr_fn(void *arg) { printf("thread start ...\n"); printf("thread exiting...\n"); pthread_exit((void *)1); } int main(void) { pthread_t tid1; int err; void* tret; err = pthread_create(&tid1, NULL, thr_fn, (void*)1); if(err != 0) err_quit("pthread_create error: %s\n", strerror(err)); err = pthread_detach(tid1); if(err != 0) err_quit("pthread_detach error: %s\n", strerror(err)); err = pthread_join(tid1,&tret); if(err != 0) err_quit("pthread_join error: %s\n", strerror(err)); printf("thread 1 exit code:%d\n",(int)tret); exit(0); }输出结果:
thread start ... thread exiting... pthread_join error: Invalid argument