pthread_attr_t 是 POSIX 线程库中用于设置和获取线程属性的数据类型。它提供了一种在创建线程前,对其行为进行精细控制的标准方法。
线程属性?
线程属性是一个不透明(opaque)的数据结构,这意味着你不能直接修改其内部成员,必须通过Pthreads库提供的一系列函数来操作。使用属性对象主要有两个好处:
- 提高代码可移植性:将属性相关的操作封装在函数中,当迁移到不同平台时,只需关注属性设置函数的差异,而无需修改创建线程的核心代码。
- 简化状态管理:你可以为不同类型的线程(如I/O密集型、计算密集型)预先配置好不同的属性对象,在创建时直接使用,使代码更清晰、易于维护。
核心操作函数
使用 pthread_attr_t 通常遵循"初始化-设置-使用-销毁"的流程。
| 函数 | 描述 |
|---|---|
pthread_attr_init(pthread_attr_t *attr) |
初始化 属性对象,将其所有属性设为默认值 。必须在pthread_create之前调用。 |
pthread_attr_destroy(pthread_attr_t *attr) |
销毁 属性对象,释放其占用的资源。销毁后,属性对象需再次初始化才能使用。注意 :销毁属性对象不会影响已经用它创建的任何线程。 |
主要线程属性及设置函数
你可以通过一系列 pthread_attr_set* 和 pthread_attr_get* 函数来管理各种线程属性。以下是几个最常用的属性:
1. 分离状态 (Detach State)
-
控制:线程结束时如何回收资源。
-
相关函数:
-
pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) -
pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) -
取值:
-
PTHREAD_CREATE_JOINABLE(默认) :线程结束后,其资源不会被自动回收,需要其他线程调用pthread_join()来回收并获取其退出状态。 -
PTHREAD_CREATE_DETACHED:线程一结束,其所有资源就会立即被系统自动回收 。该线程不能被pthread_join()。线程一旦被设为分离状态,就不能再改为可连接状态。
2. 栈大小 (Stack Size)
-
控制:为线程分配的栈空间大小(字节数),在需要控制内存占用时非常有用。
-
相关函数:
-
pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) -
pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) -
注意 :设置的值不能小于系统定义的最小值
PTHREAD_STACK_MIN。
3. 栈地址 (Stack Address)
-
控制:为新线程指定栈的起始位置(虚拟内存地址),在特殊场景下(如使用共享内存)可能需要。
-
相关函数:
-
pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) -
pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) -
默认行为:如果未设置,系统会自动为线程动态分配栈空间。
4. 调度策略与参数 (Scheduling Policy & Parameters)
-
控制:线程的调度策略和优先级,主要用于实时系统。
-
相关函数:
-
pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) -
pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) -
pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param) -
pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param) -
策略取值:
注意:后两种实时策略通常需要超级用户权限才能设置。
-
SCHED_OTHER(默认):标准的非实时分时调度策略。 -
SCHED_RR:实时轮转调度策略。 -
SCHED_FIFO:实时先进先出调度策略。
典型使用流程与代码示例
- 声明 一个
pthread_attr_t类型的变量。 - 调用
pthread_attr_init()进行初始化。 - (可选)调用各种
pthread_attr_set*()函数修改特定的属性。 - 在
pthread_create()中传入这个属性对象的指针。 - 调用
pthread_attr_destroy()销毁不再需要的属性对象。
下面的示例演示了如何创建一个分离状态(detached) 的线程:
cpp
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
static void* threadFunc(void *arg) {
printf("分离线程正在运行...\n");
// 线程结束时会自动回收资源
return NULL;
}
int main(int argc, char *argv[]) {
pthread_t thr;
pthread_attr_t attr;
int s;
/* 1. 用默认值初始化线程属性对象 */
s = pthread_attr_init(&attr);
if (s != 0) {
perror("pthread_attr_init");
exit(EXIT_FAILURE);
}
/* 2. 设置线程的分离状态属性为 "已分离" */
s = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (s != 0) {
perror("pthread_attr_setdetachstate");
exit(EXIT_FAILURE);
}
/* 3. 使用设置好的属性对象创建线程 */
s = pthread_create(&thr, &attr, threadFunc, NULL);
if (s != 0) {
perror("pthread_create");
exit(EXIT_FAILURE);
}
/* 4. 属性对象不再需要,销毁它 */
s = pthread_attr_destroy(&attr);
if (s != 0) {
perror("pthread_attr_destroy");
exit(EXIT_FAILURE);
}
/* 由于线程是分离的,无法调用 pthread_join() 等待它 */
printf("主线程结束。\n");
pthread_exit(NULL); // 确保主线程退出不会影响分离线程
}
总结
pthread_attr_t 提供了一种标准、灵活且可移植的方式来配置线程的初始行为。通过使用 pthread_attr_init() 初始化,然后用 pthread_attr_set* 系列函数设置特定属性(如分离状态、栈大小),最后在 pthread_create() 中应用这些设置,你就能精确控制线程的创建过程。
对于大多数应用,使用默认属性(即向 pthread_create 传递 NULL)就已足够。仅在需要对线程进行精细控制时,才需引入属性对象。