pthread_join函数
函数原型:
int pthread_join(pthread_t thread, void **retval);
函数返回值:
成功:0;失败:错误号
函数作用:
阻塞等待指定线程退出,并获取线程退出状态。其作用,对应进程中的waitpid() 函数。
函数参数:
thread:等待的线程ID;
retval:存储线程结束状态。由于pthread_exit函数的参数是void *,所以此处retval是void **类型。
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
char name[20];
int age;
} stu_t;
void *tfn(void *arg)
{
stu_t *student = (stu_t *)malloc(sizeof(stu_t));
if (student == NULL) {
printf("malloc failed!\n");
pthread_exit((void *)(-1));
}
memset(student, 0, sizeof(stu_t));
student->age = 20;
memcpy(student->name, "Harry", strlen("Harry"));
printf("This is a thread!\n");
pthread_exit((void *)student);
return NULL;
}
int main()
{
pthread_t tid;
stu_t *ret;
pthread_create(&tid, NULL, tfn, NULL);
pthread_join(tid, (void **)&ret);
printf("This main thread, ret->name: %s, ret->age: %d\n", ret->name, ret->age);
return 0;
}
调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:
- 如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返回值。
- 如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元里存放的是常数PTHREAD_CANCELED。
- 如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给pthread_exit的参数。
- 如果对thread线程的终止状态不感兴趣,可以传NULL给retval参数。
- 回收子线程的任何不仅仅只能通过主线程进行,任何线程都可以回收指定线程。
pthread_detach函数
函数原型:
int pthread_detach(pthread_t thread);
返回值:
成功:0;失败:错误号
函数作用:
实现线程分离。进程中无对应函数。
线程分离状态:
指定该状态,线程主动与主控线程断开关系。线程结束后,其退出状态不由其他线程获取,而直接自己自动释放。如果其它线程调用pthread_join函数来回收该线程,将得到出错信息。这种机制在网络、多线程服务器经常使用。
#include <stdio.h>
#include <pthread.h>
void *thf(void *arg)
{
printf("this is a thread\n");
pthread_exit(NULL);
}
int main()
{
pthread_t tid;
int err;
pthread_create(&tid, NULL, thf, NULL);
pthread_detach(tid);
err = pthread_join(tid, NULL);
printf("pthread_join result: %d\n", err);
return 0;
}
一般情况下,线程终止后,其终止状态一直保留到其它线程调用pthread_join获取它的状态为止。但是线程也可以被置为detach状态,这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。
不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL错误。也就是说,如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。
pthread_cancel函数
函数原型:
int pthread_cancel(pthread_t thread);
返回值:
成功:0;失败:错误号
函数作用:
杀死(取消)指定线程。其作用,对应进程中 kill() 函数。
注意:线程的取消并不是立即生效的,而是需要等待线程到达某个取消点(检查点)才可以。
所谓的取消点,可以理解为:当线程执行到某一行时,会去检查自己是否被取消了。这一行对应的函数(通常是系统调用)就是取消点。
取消点:
是线程检查是否被取消,并按请求进行动作的一个位置。通常是一些系统调用,如:creat,open,pause,close,read,write等。执行命令man 7 pthreads可以查看具备这些取消点的系统调用列表。
可粗略认为一个系统调用(进入内核)即为一个取消点。如线程中没有取消点,可以通过调用pthreestcancel函数自行设置一个取消点。
被取消的线程,退出值定义在Linux的pthread库中。通常线程被取消后,返回的错误号是PTHREAD_CANCELED,对应的值是-1。该错误号可在头文件pthread.h中找到它的定义:#define PTHREAD_CANCELED ((void *) -1)。因此当我们对一个已经被取消的线程使用pthread_join回收时,得到的返回值为-1。
总结:终止某个线程而不终止整个进程,有三种方法:
- 从线程主函数return。这种方法对主控线程不适用,从main函数return相当于调用exit。
- 一个线程可以调用pthread_cancel终止同一进程中的另一个线程。
- 线程可以调用pthread_exit终止自己。
pthread_equal函数
函数原型:
int pthread_equal(pthread_t t1, pthread_t t2);
函数作用:
比较两个线程ID是否相等。
注意:目前Linux系统下pthread_t是long int类型的,但其它平台可能是结构体实现,所以比较两个线程ID是否相等不能简单使用==来进行。
---------------
我是良许,世界500强外企 Linux 开发工程师,专业生产 Linux 干货。欢迎关注我的公众号「良许Linux」,回复「1024」获取最新最全的技术资料,回复「入群」进入高手如云技术交流群。