在 Linux 系统编程中,多线程是实现并发编程的核心手段之一。POSIX 线程(pthread)库提供了一套完整的线程操作接口,掌握这些接口的使用方式和线程属性的配置,是编写高效、稳定多线程程序的基础。本文将详细讲解 pthread 核心函数接口,并重点分析线程的分离属性及其应用场景。
一、pthread 核心函数接口详解
1. pthread_create:创建线程
pthread_create是创建线程的核心函数,调用成功后会生成一个新的线程并执行指定的任务函数。
函数原型
c
运行
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
参数说明
thread:指向pthread_t类型变量的指针,用于存储新创建线程的 ID;attr:线程属性配置,使用默认属性时传入NULL;start_routine:线程执行的函数入口,函数原型为void *(*)(void *),接收一个void*参数并返回void*;arg:传递给线程函数start_routine的参数,需通过void*类型转换适配。
返回值
- 成功:返回 0;
- 失败:返回非 0 错误码(errno 不生效,需通过返回值判断)。
2. pthread_exit:终止线程
pthread_exit用于主动终止当前线程,可指定线程退出时的返回值,供其他线程获取。
函数原型
c
运行
void pthread_exit(void *retval);
参数说明
retval:线程退出的返回值,类型为void*,可传递任意数据类型(需注意内存生命周期)。
注意事项
- 若主线程调用
pthread_exit,主线程终止但子线程仍会继续执行; - 线程函数执行完毕(return)等价于调用
pthread_exit。
3. pthread_join:阻塞回收线程
pthread_join是线程的 "等待" 接口,用于阻塞等待指定线程结束,并回收其资源,同时可获取线程的退出状态。
函数原型
c
运行
int pthread_join(pthread_t thread, void **retval);
参数说明
thread:需要等待的目标线程 ID;retval:指向void*的指针,用于存储目标线程的退出返回值(即pthread_exit的retval)。
返回值
- 成功:返回 0;
- 失败:返回非 0 错误码。
核心作用
- 回收线程资源:避免 "僵尸线程"(线程结束后资源未释放);
- 实现线程同步:主线程可通过
pthread_join等待子线程执行完毕后再继续。
4. pthread_attr_init:初始化线程属性
pthread_attr_init用于初始化线程属性对象,将其设置为系统默认值,是配置线程属性的前置操作。
函数原型
c
运行
int pthread_attr_init(pthread_attr_t *attr);
参数说明
attr:指向pthread_attr_t类型的线程属性对象,需提前分配内存(如栈上声明)。
返回值
- 成功:返回 0;
- 失败:返回非 0 错误码。
5. pthread_attr_destroy:销毁线程属性
pthread_attr_destroy用于销毁已初始化的线程属性对象,释放其占用的资源。
函数原型
c
运行
int pthread_attr_destroy(pthread_attr_t *attr);
参数说明
attr:已初始化的线程属性对象。
返回值
- 成功:返回 0;
- 失败:返回非 0 错误码。
6. pthread_attr_setdetachstate:设置线程分离属性
pthread_attr_setdetachstate是线程属性配置的核心函数之一,用于设置线程的 "加入 / 分离" 属性。
函数原型
c
运行
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
参数说明
attr:已初始化的线程属性对象;detachstate:线程分离状态,可选值:PTHREAD_CREATE_DETACHED:分离属性;PTHREAD_CREATE_JOINABLE:加入属性(默认值)。
返回值
- 成功:返回 0;
- 失败:返回非 0 错误码。
二、线程的分离属性深度解析
线程的分离属性(detachstate)决定了线程结束后资源的回收方式,是多线程编程中必须重点关注的属性。
1. 两种属性对比
表格
| 属性类型 | 核心特点 | 适用场景 |
|---|---|---|
| 加入属性(JOINABLE) | 线程结束后需手动调用pthread_join回收资源;可获取线程退出状态;实现同步 |
需要等待线程执行结果的场景 |
| 分离属性(DETACHED) | 线程结束后系统自动回收资源;无需调用pthread_join;无法获取退出状态 |
无需等待线程结果的后台任务 |
2. 关键注意事项
- 若线程为 JOINABLE 属性但未调用
pthread_join,线程结束后会成为 "僵尸线程",占用系统资源; - 分离属性的线程调用
pthread_join会返回错误(EINVAL); - 可通过
pthread_detach函数在线程创建后动态设置分离属性(无需提前配置属性对象)。
三、实战示例:不同属性线程的创建与回收
示例 1:默认属性(JOINABLE)线程
c
运行
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
// 线程函数
void *thread_func(void *arg) {
int num = *(int *)arg;
printf("线程 %d 执行中\n", num);
// 线程退出,返回值为num+100
pthread_exit((void *)(num + 100));
}
int main() {
pthread_t tid;
int arg = 1;
void *retval;
// 创建默认属性线程(JOINABLE)
int ret = pthread_create(&tid, NULL, thread_func, &arg);
if (ret != 0) {
perror("pthread_create failed");
exit(1);
}
// 阻塞等待线程结束,回收资源并获取返回值
ret = pthread_join(tid, &retval);
if (ret != 0) {
perror("pthread_join failed");
exit(1);
}
printf("线程结束,返回值:%ld\n", (long)retval);
return 0;
}
示例 2:分离属性(DETACHED)线程
c
运行
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
// 线程函数
void *thread_func(void *arg) {
int num = *(int *)arg;
printf("分离线程 %d 执行中\n", num);
// 分离线程无需返回值,系统自动回收
sleep(2);
printf("分离线程 %d 执行完毕\n", num);
return NULL;
}
int main() {
pthread_t tid;
pthread_attr_t attr;
int arg = 2;
// 初始化线程属性
int ret = pthread_attr_init(&attr);
if (ret != 0) {
perror("pthread_attr_init failed");
exit(1);
}
// 设置分离属性
ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (ret != 0) {
perror("pthread_attr_setdetachstate failed");
exit(1);
}
// 创建分离属性线程
ret = pthread_create(&tid, &attr, thread_func, &arg);
if (ret != 0) {
perror("pthread_create failed");
exit(1);
}
// 销毁属性对象
pthread_attr_destroy(&attr);
// 主线程等待子线程执行完毕(仅为演示,实际无需join)
sleep(3);
printf("主线程结束\n");
return 0;
}
编译与运行
编译时需链接 pthread 库(-lpthread):
bash
运行
gcc thread_demo.c -o thread_demo -lpthread
./thread_demo
四、总结
- 核心函数 :
pthread_create创建线程、pthread_exit终止线程、pthread_join回收 JOINABLE 线程资源,pthread_attr_init/destroy用于线程属性的初始化与销毁; - 分离属性 :JOINABLE 线程需手动
pthread_join回收(可获取退出状态),DETACHED 线程由系统自动回收(无需 join); - 使用原则:无需等待线程结果时优先使用分离属性,避免僵尸线程;需要同步或获取线程执行结果时使用 JOINABLE 属性。
掌握 pthread 核心接口和分离属性的使用,能有效提升多线程程序的稳定性和资源利用率,是 Linux 系统编程的必备技能。