1,如何退出一个线程
- return 线程执行的那个函数返回了;
- 线程可以被同一进程中的其他线程取消 :pthread_cancel;
- 线程调用 pthread_exit,退出当前线程而不退出进程。
注意:如果在线程里调用exit、_exit、_Exit,退出的不是当前线程,而是整个进程。
#include <pthread.h>
void pthread_exit(void *rval_ptr);
rval_ptr是这个线程退出时的返回值的地址。
当一个线程退出后,它的栈资源会被自动回收吗?并不一定。这取决于这个线程是可分离的还是可结合的。
2,线程的分离与结合
在任何一个时间点上,线程要么是可结合的(joinable),要么是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的。相反,一个可分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。而线程被创建后的默认状态是可结合的。
所以,第一个问题是,如何回收可结合线程的资源?
3,pthread_join
在Linux平台默认情况下,虽然各个线程之间是相互独立的,一个线程的终止不会去通知或影响其他的线程。但是已经终止的线程(可结合线程)的资源并不会随着线程的终止而得到释放,我们需要调用 pthread_join() 来获得另一个线程的终止状态并且释放该线程所占的资源。它类似于进程里的waitpid.
#include<pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
调用这个函数的线程将一直阻塞(等待),直到由输入参数thread指定的线程退出(通过第一节所说的3种方法中的任意一种)。
关于rval_ptr指向的内容:
- 线程是通过return返回的,则rval_ptr就包含了返回码;
- 线程是被其他线程取消掉的,则rval_ptr指向的内容会被设为PTHREAD_CANCELED;
- 线程是通过pthread_exit退出的,则rval_ptr指向的内容由pthread_exit指定.
- 如果我们对线程的返回值不感兴趣,可以直接把rval_ptr设为NULL。
经过这个函数的调用后,那个由thread指定的线程就进入了分离态,它的资源就可以被回收了。如果在调用这个函数之前,线程已经处于分离态了,则调用失败,返回错误码。调用前线程不可以是已分离的,但可以是已退出的。
从上面的说明中,我们可以发现,通过将pthread_exit与pthread_join配合使用,我们就可以在一个线程结束的时候给另一个线程传递任意内容。实际上我们传递的是一个地址,但是注意,这个地址千万不要是那个马上要退出的线程的局部变量的地址。因为前面已经说过,这个线程的资源在pthread_join之后马上就回收了,所以传递出来的地址也是无效的。
4,例子
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
//声明要在线程里执行的函数
void* thr_fn1(void *arg);
void* thr_fn2(void *arg);
int main(){
//11.5
int err; //错误码
pthread_t tid1, tid2; //线程ID
void* tret; //线程的返回值
//创建两个线程
err = pthread_create(&tid1, NULL, thr_fn1, NULL);
if (err)
err_sys("creat thread 1 error!");
err = pthread_create(&tid2, NULL, thr_fn2, NULL);
if (err)
err_sys("creat thread 2 error!");
printf("after created two threads.\n");
//等待两个线程结束
err = pthread_join(tid1, &tret);
if (err)
err_sys("join thread 1 error!");
printf("thread 1 exit code %ld\n", (long)tret);
err = pthread_join(tid2, &tret);
if (err)
err_sys("join thread 2 error!");
printf("thread 2 exit code %ld\n", (long)tret);
exit(0);
}
//线程里函数的定义
void* thr_fn1(void *arg)
{
printf("thread 1, return\n");
return((void*)1); //注意这种返回方式
}
void* thr_fn2(void *arg)
{
printf("thread 2, exit\n");
pthread_exit((void*)2); //注意这种返回方式
}
执行结果如下:
➜ code gcc -g -W -o study_Linux study_Linux.c -lpthread
➜ code ./study_Linux
thread 1, return
after created two threads.
thread 2, exit
thread 1 exit code 1
thread 2 exit code 2
注意,64位下,指针类型的长度与long相同,而不是int。
5,分离线程
前面的例子说的是,回收结合态线程的资源。那如何分离一个线程呢?毕竟分离之后就不用手动回收资源了。
调用如下函数即可。
#include<pthread.h>
int pthread_detach(pthread_t tid);