Linux 下有两种方式可以使线程终止,一种是通过return从线程函数返回,第二种是通过调用pthread_exit()使线程退出
pthread_exit
是一个线程库中的函数,用于终止调用线程。该函数的原型如下:
#include <pthread.h>
void pthread_exit(void *retval);
retval
参数是一个指向线程的返回值的指针。这个返回值可以通过其他线程调用pthread_join
函数来获取。调用
pthread_exit
将会终止当前线程,并将retval
的值传递给等待该线程的任何调用pthread_join
的线程。如果线程没有被任何其他线程等待,它的资源将会在终止时被释放。
有两种特殊情况要注意:一种情况是, 在主线程中,如果从main函数返回或是调用了exit
函数退出主线程,则整个进程将终止,此时进程中所有线程也将终止,因此在主线程中不能过
早地从main函数返回;另种情是如果主线程调用pthread_ exit 函数,则仅仅是主线程消亡,进
程不会结束,进程内的其他线程也不会终止,直到所有线程结束,进程才会结束。
线程终止最重要的问题是资源释放的问题,特别是一些临界资源。临界资源在一段时间内只
能被一个线程所持有,当线程要使用临界资源时需提出请求,如果该资源未被使用则申请成功,
否则等待。临界资源使用完毕后要释放以便其他线程可以使用。例如,某线程要写-一个文件,在
写文件时一般不允许其他线程也对该文件执行写操作的,否则会导致文件数据混乱。这里的文件
就是一种临界资源。临界资源为一个线程所独占,当一个线程终止时,如果不释放其占有的临界
资源,则该资源会被认为还被已经退出的线程所使用,因而永远不会得到释放。如果一个线程在
等待使用这个临界资源,它就可能无限的等待下去,这就形成了死锁。
为此linux提供了一对函数用于自动释放资源
pthread_cleanup_push和pthread_cleanup_pop
pthread_cleanup_push
通常与pthread_cleanup_pop
一起使用。这对函数提供了一种在线程退出时执行特定操作的机制,而不是直接在线程函数中使用return
。以下是
pthread_cleanup_push
的原型:
#include <pthread.h>
void pthread_cleanup_push(void (*routine)(void *), void *arg);
routine
参数是一个指向清理函数的指针,该函数将在线程退出时执行。arg
参数是传递给清理函数的参数。
#include <pthread.h>
void pthread_cleanup_pop(int execute);
execute
参数是一个整数值,如果execute
的值为非零,则表示执行注册的清理函数;如果为零,则表示不执行清理函数。这提供了一种选择性地执行清理函数的机制。
意思即是线程退出时会执行routine指定的函数。
这两函数必须成对出现。
pthread_join函数
这个函数用来等待一个指定线程的结束。调用pthread_join的线程会被挂起等待某个线程终止
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
thread
参数是要等待的线程的标识符。retval
参数是一个指向指针的指针,用于接收目标线程的退出状态。调用
pthread_join
的线程会一直阻塞,直到指定的线程(通过thread
参数指定)退出。一旦目标线程退出,pthread_join
会解除阻塞,并将目标线程的退出状态存储在retval
指向的位置。
一个线程只能被一个线程等待,不能多个线程都等待同一个线程。
同时,被等待的那个线程不能说detached的状态,即分离状态。对某个线程调用pthread_detach可使它变为detached状态。这时该线程在后台运行,会自动释放资源。
一个joinable线程所占用的内存仅当有线程对其执行了pthread_join才会释放。
所以一个线程要么是detached,要么通过pthread_join来回收它的资源。
书上的示例程序好像不太对,我改了一下。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
void *assistthread(void *arg){
printf("i am helping to do some jobs\n");
sleep(3);
int *result=(int *)malloc(sizeof(int));
*result=42;
pthread_exit((void *)result);
}
int main(){
pthread_t assistthid;
int *status;
pthread_create(&assistthid,nullptr,assistthread,nullptr);
pthread_join(assistthid,(void **)&status);
printf("assistthread's exit is caused %d\n",*status);
free(status);
return 0;
}
可以看到主线程通过status来接受assist线程通过pthread_exit传出来的结束状态。