Linux学习笔记24——线程终止 pthread_join

1,如何退出一个线程

  1. return  线程执行的那个函数返回了;
  2. 线程可以被同一进程中的其他线程取消 :pthread_cancel;
  3. 线程调用 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指向的内容:

  1. 线程是通过return返回的,则rval_ptr就包含了返回码;
  2. 线程是被其他线程取消掉的,则rval_ptr指向的内容会被设为PTHREAD_CANCELED;
  3. 线程是通过pthread_exit退出的,则rval_ptr指向的内容由pthread_exit指定.
  4. 如果我们对线程的返回值不感兴趣,可以直接把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);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值