线程退出中exit 和pthread_exit的区别
进程的终止可以通过在主函数main()中直接调用exit、return,或者通过进程中的任何其它线程调用exit来实现。在任何一种情况下,该进程的所有线程都会终止。
而pthread_exit函数则是使调用改函数的线程中止运行,并且允许线程传递一个指针。它的形式为:
void pthread_exit(void *value_ptr) ;
连接了这个线程可以获得参数value_ptr的值。回顾前面介绍的pthread_join函数,这个函数的参数void **value_ptr,正是保存pthread_exit函数的参数void *value_ptr的地址。这里要注意,pthread_exit的参数value_ptr必须指向线程退出后仍然存在的数据。
例1
#include <unistd.h>
#include <semaphore.h>
#include <sys/types.h>
#include <dirent.h>
#include <pthread.h>
#include <errno.h>
#include <signal.h>
#include <time.h>
#include <stdio.h>
void * thread_child(void *arg)
{
while(1)
{
usleep(500*1000);
printf("thread_child running!\n");
}
return NULL;
}
int main(int argc,char** argv)
{
pthread_t tid;
int i = 0;
pthread_create(&tid, NULL, (void*)thread_child, &i);
for(i=0;i<5;i++)
{
usleep(1000*1000);
printf("main thread running!\n");
}
printf("Leave main thread!\n");
return 0;
}
运行结果
例2
#include <unistd.h>
#include <semaphore.h>
#include <sys/types.h>
#include <dirent.h>
#include <pthread.h>
#include <errno.h>
#include <signal.h>
#include <time.h>
#include <stdio.h>
void * thread_child(void *arg)
{
while(1)
{
usleep(500*1000);
printf("thread_child running!\n");
}
return NULL;
}
int main(int argc,char** argv)
{
pthread_t tid;
int i = 0;
pthread_create(&tid, NULL, (void*)thread_child, &i);
for(i=0;i<5;i++)
{
usleep(1000*1000);
printf("main thread running!\n");
}
printf("Leave main thread!\n");
pthread_exit(NULL);
return 0;
}
运行结果
结果分析
在例2中因为调用了pthread_exit而没有执行到return,导致主线程main停止了,但是改进程中的子线程还在继续运行,一直打印“thread_child running!”。
例3
#include <unistd.h>
#include <semaphore.h>
#include <sys/types.h>
#include <dirent.h>
#include <pthread.h>
#include <errno.h>
#include <signal.h>
#include <time.h>
#include <stdio.h>
void * thread_child(void *arg)
{
int i;
for(i=0;i<5;i++)
{
usleep(500*1000);
printf("thread_child running!\n");
}
pthread_exit(&i);
}
int main(int argc,char** argv)
{
pthread_t tid;
int **p;
int *q;
int a=120;
q=&a;
p=&q;
pthread_create(&tid, NULL, (void*)thread_child, NULL);
pthread_join(tid,(void **)p);
printf("thread_chile exit i = %d\n",**p);
printf("Leave main thread!\n");
return 0;
}
运行结果
结果分析
在例3中正常运行结果,i的值应该是5,但是多次运行以后会发现最后i的值是一直变化的,这是因为pthread_exit的参数value_ptr必须指向线程退出后仍然存在的数据,而子线程thread_child运行结束以后临时变量i就被释放掉了。所以要获得正确的结果就必须把i设为全局变量。还有一点在本例main函数中必须先给指针的指针p指定一个变量,不然执行到printf(“thread_chile exit i = %d\n”,**p);会报错。
取消线程
线程也可以通过取消机制迫使其它的线程退出。线程可以调用函数pthread_cancel来请求取消另一个线程。这个函数的形式是:
int pthread_cancel(pthread_t thread);
参数thread是要取消的目标线程的线程ID。该函数并不阻塞调用线程,它发出取消请求后就返回了。如果成功,pthread_cancel返回0,如果不成功,pthread_cancel返回一个非零的错误码。
线程收到一个取消请求时会发生什么情况取决于它的状态和类型。如果线程处于PTHREAD_CANCEL_ENABLE状态,它就接受取消请求,如果线程处于PTHREAD_CANCEL_DISABLE状态,取消请求就会被保持在挂起状态。默认情况下,线程处于PTHREAD_CANCEL_ENABLE状态。
pthread_setcancelstate函数用来改变调用线程的取消状态,它的形式为:
int pthread_setcancelstate(int state, int *oldstate);
参数state表示要设置的新状态,参数oldstate为一个指向整形的指针,用于保存线程以前的状态。如果成功,该函数返回0,如果不成功,它返回一个非0的错误码。通常情况下,线程函数在改变了线程的取消状态之后,应该在执行完某些操作之后恢复线程的取消状态,否则,对于其它可能取消该线程的线程而言,取消操作的结果将无法预测,这很可能不利于程序的正确运行。
例4
#include <unistd.h>
#include <semaphore.h>
#include <sys/types.h>
#include <dirent.h>
#include <pthread.h>
#include <errno.h>
#include <signal.h>
#include <time.h>
#include <stdio.h>
void * thread_child(void *arg)
{
int i;
for(i=0;i<5;i++)
{
usleep(500*1000);
printf("thread_child running!\n");
}
return NULL;
}
int main(int argc,char** argv)
{
pthread_t tid;
pthread_create(&tid, NULL, (void*)thread_child, NULL);
usleep(500*1000);
printf("stop thread_chile!\n");
pthread_cancel(tid);
printf("Leave main thread!\n");
return 0;
}