pthread 简要使用指南(三) 线程的终止
pthread_create()的帮助文档里面,明确指出,一个线程的终止有如下的四种方式:
* 本线程中调用pthread_exit(),同一进程里面调用pthread_join()的其他线程可以获取该线程的退出值。
* 本线程的线程函数start_routine执行结束返回。
* 本线程被pthread_cancel()取消。
* 本线程所在的进程退出。
pthread_exit(), 原型:
void pthread_exit(void *retval);
该函数在线程中的作用,与exit()在进程中的作用类似。执行到pthread_exit(),线程将会直接终止,并使用pthread_exit的参数作为线程的退出状态值。如果线程是joinable的,其线程ID和退出状态值将一直保留到调用进程中的某个其他线程调用pthread_join函数。指针retval不能指向局部于调用线程的对象,因为线程终止时这些对象也消失。
pthread_cancel(),原型:
int pthread_cancel(pthread_t thread);
pthread_cancel()发送一个取消请求给目标线程,该函数需要目标线程配合。目标线程如何操作,取决于该线程的可撤销状态及类型(cancelability state and type)。
可撤销状态有两个值:PTHREAD_CANCEL_ENABLE,PTHREAD_CANCEL_DISABLE。该状态可以通过pthread_setcancelstate()函数来修改。这个状态决定该线程是否处理取消请求。如果PTHREAD_CANCEL_ENABLE,则处理取消请求,PTHREAD_CANCEL_DISABLE,则不处理取消请求。
可撤销类型同样也有两个值:PTHREAD_CANCEL_DEFERRED,PTHREAD_CANCEL_ASYNCHRONOUS。该类型可以通过pthread_setcanceltype()函数来修改。可撤销状态为PTHREAD_CANCEL_ENABLE时,可撤销类型值才会被判断。PTHREAD_CANCEL_ASYNCHRONOUS 立即执行取消信号,PTHREAD_CANCEL_DEFERRED 运行到下一个取消点然后退出线程。
PTHREAD_CANCEL_DEFERRED情形下,pthread_cancel()给目标线程设置一个取消标志。目标线程在运行中的某些地方会查看自己是否存在取消请求,如果有,就立刻终止执行后继代码并退出。这些查看是否存在取消请求的地方,称之为取消点(Cancelation-point)。
下面的代码,是在suse linux中的pthread_cancel编程指南中例子的基础上修改得到:
#include <pthread.h>#include <stdio.h>#include <errno.h>#include <stdlib.h>#include <unistd.h>#define handle_error_en(en, msg) \ do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)static void * thread_func(void *ignored_argument){ int s; pthread_t *pthr = (pthread_t *)ignored_argument; /* Disable cancellation for a while, so that we don't immediately react to a cancellation request */ s = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); if (s != 0) handle_error_en(s, "pthread_setcancelstate"); printf("thread_func(id %u (0x%x)): started; cancellation disabled\n", (unsigned int)(*pthr), (unsigned int)(*pthr)); sleep(5); printf("thread_func(id %u (0x%x)): about to enable cancellation\n", (unsigned int)(*pthr), (unsigned int)(*pthr)); s = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); if (s != 0) handle_error_en(s, "pthread_setcancelstate"); /* sleep() is a cancellation point */ sleep(10); /* Should get canceled while we sleep */ /* Should never get here */ printf("thread_func(id %u (0x%x)): not canceled!\n", (unsigned int)(*pthr), (unsigned int)(*pthr)); return NULL;}int main(void){ pthread_t thr1; pthread_t thr2; void *res; int s; /* Start a thread and then send it a cancellation request */ s = pthread_create(&thr1, NULL, &thread_func, (void*)&thr1); if (s != 0) handle_error_en(s, "pthread_create 1"); s = pthread_create(&thr2, NULL, &thread_func, (void*)&thr2); if (s != 0) handle_error_en(s, "pthread_create 2"); sleep(2); /* Give thread a chance to get started */ printf("main(): sending cancellation request\n"); s = pthread_cancel(thr1); if (s != 0) handle_error_en(s, "pthread_cancel"); /* Join with thread to see what its exit status was */ s = pthread_join(thr1, &res); if (s != 0) handle_error_en(s, "pthread_join"); if (res == PTHREAD_CANCELED) printf("main(): thread 1 was canceled\n"); else printf("main(): thread 1 wasn't canceled (shouldn't happen!)\n"); s = pthread_join(thr2, &res); if (s != 0) handle_error_en(s, "pthread_join"); if (res == PTHREAD_CANCELED) printf("main(): thread 2 was canceled\n"); else printf("main(): thread 2 wasn't canceled (shouldn't happen!)\n"); exit(EXIT_SUCCESS);}