linux环境下使用pthread_exit来终止进程,
void pthread_exit(void *rval_ptr);
参数是一个指向任意类型的指针,该指针指向的区域存储退出信息,该信息类似于传递给新线程的参数,可以将多个信息组织成一个结构体。
当一个线程结束运行时,其结束信息的地址保存在内核中,其他的线程可以引用此线程的结束信息。
linux环境下使用pthread_join函数来访问指定线程的结束信息。
int pthread_join(pthread_t tid,void **rval_ptr);
第一个参数表示需要取得结束信息的线程,如果该线程还在运行中,那么pthread_join函数会导致调用线程的阻塞,直到指定的线程结束执行为止。如果指定线程的线程ID和调用线程不属于同一个进程,则pthread_join函数出错返回。这一点说明不同进程的线程之间的通信远不像属于同一进程的线程那样简单,事实上其通信方式类似于进程之间的通信方式。
第二个参数是一个指向任意类型指针的指针。由于pthread_join函数负责从内核中得到指定线程结束信息的地址,这是一个指针,因为要在内核中改变它的值,所以该参数的类型为指针的指针。如果线程由于线程体函数返回或者调用pthread_exit函数退出,则rval_ptr指向的是退出信息的首地址,如果线程由于被其他线程取消而退出,则rval_ptr被设置为PTHREAD_CANCELED.
如果调用线程对指定线程的退出信息并不关心,可以讲rval_ptr参数设置为NULL,这时调用线程仅仅等待指定线程结束执行,而不获得线程退出信息。如果成功得到指定线程的退出信息,pthread_join函数返回0,失败则返回错误号。
- #include <stdio.h>
- #include <stdlib.h>
- #include <pthread.h>
- #include <unistd.h>
- void *func1(void *arg)
- {
- printf("the first\n");
- return (void *)1;
- }
- void *func2(void *arg)
- {
- printf("the second\n");
- pthread_exit((void*)3);
- printf("should not be here!\n");
- }
- void *func3(void *arg)
- {
- sleep(10);
- printf("the third,sleep 10 seconds\n");
-
- return NULL;
- }
- int main(void)
- {
- pthread_t tid1,tid2,tid3;
- void *res;
- int err;
-
- //thread1
- err = pthread_create(&tid1, NULL,func1,NULL); //创建第一个线程
- if(err!=0)
- {
- printf("failed to create thread %s\n",strerror(err));
- exit(1);
- }
-
- err = pthread_join(tid1,&res); //等待线程退出,并获得退出消息
- if(err!=0)
- {
- printf("can't join thread1 %s\n",strerror(err));
- exit(1);
- }
- printf("result from thread1:%d\n",(unsigned int )(res));//输出提示信息
-
- //thread2
- err = pthread_create(&tid2, NULL,func2,NULL);
- if(err!=0)
- {
- printf("failed to create thread %s\n",strerror(err));
- exit(1);
- }
-
- err = pthread_join(tid2,&res); //等待线程退出,并获得退出消息
- if(err!=0)
- {
- printf("can't join thread2 %s\n",strerror(err));
- exit(1);
- }
- printf("result from thread2:%d\n",(unsigned int )(res));//输出提示信息
-
-
- //thread3
- err = pthread_create(&tid3, NULL,func3,NULL);
- if(err!=0)
- {
- printf("failed to create thread %s\n",strerror(err));
- exit(1);
- }
-
- err = pthread_join(tid3,&res); //等待线程退出,并获得退出消息
- if(err!=0)
- {
- printf("can't join thread2 %s\n",strerror(err));
- exit(1);
- }
- printf("result from thread3:%d\n",(unsigned int )(res));//输出提示信息
-
- printf("the third thread is done\n");
- return 0;
-
- }
- the first
- result from thread1:1
- the second
- result from thread2:3
- (10s钟之后)
- the third,sleep 10 seconds
- result from thread3:0
- the third thread is done
6.正确得到线程退出信息的方法
在线程结束运行后,linux内核中保存的只是存储退出信息内存区域的首地址,而并未将退出信息实际保存在内核中,因此,在线程结束运行后,其保存退出信息的内存区域仍然是有效的。所以不能将退出信息存储在局部变量中,而应该使用动态分配的内存或者全局变量。
就是说数据不要保存在函数的栈帧中,
7.取消一个线程的运行
一个进程可以通过发送信号的方式使另一个进程结束运行,如调用kill函数发送SIGKILL信号。同进程一样,一个线程也可以被另一个线程取消掉。
linux环境下使用pthread_cancel函数取消另一个线程
int pthread_cancel(pthread_t tid);
参数是实际要取消线程的ID,取消成功,返回0,失败返回错误编号。
调用该函数等效于线程自己调用pthread_exit(PTHREAD_CANCELED);
8.线程退出函数
同进程一样,一个线程在退出时可以调用用户设置好的函数,这些函数称为线程清理程序,记录在栈中,linux环境下使用pthread_cleanup_push函数添加一个清理程序记录,使用pthread_cleanup_pop函数调用清理程序。
void pthread_cleanup_push(void (*rtn)(void *),void *arg);
void pthread_cleanup_pop(int execute);
push函数的第一个参数是一个函数指针,指向清理程序,清理程序是一个没有返回值的函数,其参数是一个任意类型的指针。
pop函数的参数表示是否执行栈顶的清理程序,参数execute为0,表示不执行,但是将栈顶的清理程序记录出栈;参数非零,表示执行栈顶清理程序,执行之后该记录也会出栈。
从pthread_cleanup_push的调用点到pthread_cleanup_pop 之间的程序段中的终止动作(包括pthread_exit和异常终止,不包括return)都将执行pthread_cleanup_push所指定的清理函数。
PS:
linux环境,sleep可以用于线程或进程的睡眠。
sleep的安全性问题:(从网上搜得)
unix 环境高级编程有对sleep详细说明
在线程中使用sleep 不安全的原因是在有些平台下sleep是用alarm函数实现的,与信号相关,而信号是针对于进程的, 在线程下使用不安全。
FreeBSD5.2.1、linux 2.4.22和Mac 0SX 10.3 用nanosleep提供延迟。该函数可以使sleep的实现与信号无关.
还有一法,select:
select( 1, NULL, NULL, NULL, & timeout );