使用pthread_create()函数创建线程的时候,函数的第二个参数attr用于指定新线程的属性,通常在创建线程之前通过 pthread_attr_t 类型的变量来配置线程属性。在不同的操作系统实现中,pthread_attr_t 的底层数据结构可能会有所不同,但我们不直接访问它的内部成员,而是通过 POSIX 提供的 pthread_attr_* 函数接口来初始化、设置或查询其属性。

简单介绍一下与线程属性相关的API接口:

相关API

简要说明

基本属性管理

pthread_attr_init (pthread_attr_t *__attr)

初始化 pthread_attr_t

pthread_attr_destroy (pthread_attr_t *__attr)

销毁属性对象,释放相关资源。

线程分离状态

pthread_attr_getdetachstate(const pthread_attr_t *__attr, int *__detachstate)

获取线程的分离状态属性,放入 __detachstate。

pthread_attr_setdetachstate (pthread_attr_t *__attr, int __detachstate)

设置线程的分离状态属性。

栈和保护区大小

pthread_attr_getguardsize (const pthread_attr_t *__attr, size_t *__guardsize)

获取线程栈末尾的警戒缓冲区大小(防止栈溢出区域),单位是字节。

pthread_attr_setguardsize (pthread_attr_t *__attr, size_t __guardsize)

设置线程栈末尾的警戒缓冲区大小。

pthread_attr_getstackaddr (const pthread_attr_t *__restrict __attr, void **__restrict __stackaddr)

获取线程栈的起始地址。(返回先前设置的堆栈地址)

pthread_attr_setstackaddr (pthread_attr_t *__attr, void *__stackaddr)

设置线程栈的起始地址。根据堆栈是增加还是减少,该值必须高于或低于内存块中的所有地址。

pthread_attr_getstacksize (const pthread_attr_t *__restrict __attr, size_t *__restrict __stacksize)

获取线程栈的大小。(返回当前使用的最小堆栈大小)

pthread_attr_setstacksize (pthread_attr_t *__attr, size_t __stacksize)

设置线程栈的大小。(添加有关启动线程所需的最小堆栈大小的信息。这个大小不能小于PTHREAD_STACK_MIN,也不能超过系统限制。)

调度策略和优先级

pthread_attr_getschedparam (const pthread_attr_t *__restrict __attr, struct sched_param *__restrict __param)

获取线程的调度参数(优先级),放入 __param。

pthread_attr_setschedparam (pthread_attr_t *__restrict __attr, const struct sched_param *__restrict __param)

设置线程的调度参数(优先级)。

pthread_attr_getschedpolicy (const pthread_attr_t *__restrict __attr, int *__restrict __policy)

获取线程的调度策略(如 SCHED_FIFO、SCHED_RR、SCHED_OTHER)

pthread_attr_setschedpolicy (pthread_attr_t *__attr, int __policy)

设置线程的调度策略。

继承和调度范围

pthread_attr_getinheritsched (const pthread_attr_t *__restrict __attr, int *__restrict __inherit)

获取线程的调度属性继承方式,可以是 PTHREAD_INHERIT_SCHED 或 PTHREAD_EXPLICIT_SCHED。

pthread_attr_setinheritsched (pthread_attr_t *__attr, int __inherit)

设置线程的调度属性继承方式。

pthread_attr_getscope (const pthread_attr_t *__restrict __attr, int *__restrict __scope)

获取线程的作用域,可以是 PTHREAD_SCOPE_SYSTEM(系统范围)或 PTHREAD_SCOPE_PROCESS(进程内部范围)。

pthread_attr_setscope (pthread_attr_t *__attr, int __scope)

设置线程的作用域。

栈和亲和性(Linux特有)

pthread_attr_getstack (const pthread_attr_t *__restrict __attr, void **__restrict __stackaddr, size_t *__restrict __stacksize)

获取线程栈的起始地址和大小。

pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, size_t __stacksize)

设置线程栈的起始地址和大小。

pthread_attr_setaffinity_np (pthread_attr_t *__attr, size_t __cpusetsize, const cpu_set_t *__cpuset)

设置线程的 CPU 亲和性,限制线程在哪些 CPU 上运行(非标准接口)。

pthread_attr_getaffinity_np (const pthread_attr_t *__attr, size_t __cpusetsize, cpu_set_t *__cpuset)

获取线程的 CPU 亲和性(非标准接口)。

其他相关接口

pthread_getattr_default_np (pthread_attr_t *__attr)

获取系统默认的线程属性(Linux扩展)。

pthread_setattr_default_np (const pthread_attr_t *__attr)

设置系统默认的线程属性(Linux扩展)。

pthread_attr_setsigmask_np (pthread_attr_t *__attr, const __sigset_t *sigmask)

设置线程的信号掩码(Linux扩展)。

pthread_attr_getsigmask_np (const pthread_attr_t *__attr, __sigset_t *sigmask)

获取线程的信号掩码(Linux扩展)。

pthread_getattr_np (pthread_t __th, pthread_attr_t *__attr)

获取现有线程的属性,适用于调试或复制线程配置。

这些函数使得对线程属性的管理更灵活,例如在设置优先级或栈大小时,可以根据需要对线程进行细粒度控制。

1.相关参数大致说明

1)pthread_attr_t

描述:线程属性对象,包含了线程的各种属性设置,如栈大小、调度策略、分离状态等。

2)int(整型参数)

用途:常用于获取或设置线程的状态,例如分离状态、调度策略等。

·detachstate:表示线程的分离状态,取值为 PTHREAD_CREATE_JOINABLE(可连接)或 PTHREAD_CREATE_DETACHED(已分离)。

·inherit:表示调度继承状态,取值为 PTHREAD_INHERIT_SCHED 或 PTHREAD_EXPLICIT_SCHED。

·scope:表示调度范围,取值为 PTHREAD_SCOPE_SYSTEM 或 PTHREAD_SCOPE_PROCESS。

3)struct sched_param

描述:调度参数结构体,包含线程的优先级设置。

主要成员:int sched_priority:表示线程的调度优先级。

4)size_t

描述:用于表示大小的无符号整型,常用于栈大小和保护区大小等。

·guardsize:保护区大小,指定在栈顶和栈底之间的保护区大小。

·stacksize:栈大小,指定线程的栈的大小。

5)void *(指针参数)

用途:用于指向特定的资源,如栈地址或 CPU 亲和性集等。

·stackaddr:线程栈的起始地址,用户可以通过设置这个参数来指定线程的栈位置。

·cpuset:CPU 亲和性集,用于指定线程可以运行在哪些 CPU 上。

6)cpu_set_t

描述:用于表示 CPU 亲和性集的数据结构,可以通过设置和获取特定 CPU 的亲和性。

用途:在设置线程的 CPU 亲和性时使用。

如果没有其他特别的需求,可以直接使用默认属性,不需要考虑线程相关属性的情况pthread_create()函数的第二个参数可以设置为NULL;如果需要配置用到线程的相关属性,通常会先创建一个属性对象,然后在属性对象上设置属性的值,再将属性对象传给pthread_create()函数的第二个参数;

2.使用线程属性的流程步骤一般如下

1)定义一个 pthread_attr_t 类型的变量:这个结构体用于存储线程属性。

2)初始化线程属性:使用 pthread_attr_init() 函数来初始化线程属性。

3)设置所需的线程属性:使用各种 pthread_attr_set*() 函数设置具体的属性,例如设置栈大小、调度策略等。

4)创建线程并传递属性:在调用 pthread_create() 时,将属性传递给它。

5)销毁线程属性:使用 pthread_attr_destroy() 来释放相关资源。

3.示例:使用线程属性创建一个分离线程

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

#include <unistd.h>

void* thread_function(void* arg) {

    printf("Thread is running...\n");

    sleep(2); // 模拟线程工作

    printf("Thread is exiting...\n");

    return NULL;

}

int main() {

    pthread_t thread;

    pthread_attr_t attr;

    // 初始化线程属性

    pthread_attr_init(&attr);

    

    // 设置线程为分离状态

    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    // 创建线程

    if (pthread_create(&thread, &attr, thread_function, NULL) != 0) {

        perror("Failed to create thread");

        exit(EXIT_FAILURE);

    }

    // 销毁线程属性

    pthread_attr_destroy(&attr);

    // 主线程继续执行

    printf("Main thread is running...\n");

    

    // 由于子线程是分离状态,主线程不需要调用 pthread_join

    sleep(3); // 等待子线程完成工作

    printf("Main thread is exiting...\n");

    

    return 0;

}

4.运行结果

Main thread is running...

Thread is running...

Thread is exiting...

Main thread is exiting...

5.代码解析

thread_function()定义一个线程将要执行的函数。pthread_t thread;定义一个线程标识符 thread,用于识别和管理线程。pthread_attr_t attr;定义一个线程属性对象 attr,用于设置线程的属性。使用 pthread_attr_init 初始化 attr 属性对象,以便后续配置线程属性。调用 pthread_attr_setdetachstate 设置线程为分离状态。分离线程在结束时会自动释放其占用的资源,不需要主线程调用 pthread_join。pthread_create()函数调用属性参数,最后销毁属性对象,然后释放相关资源。

可以将同一个线程属性对象 pthread_attr_t 应用于多个线程。这种方式有助于统一配置多个线程的属性,从而简化代码的维护和管理。设置完线程属性对象 pthread_attr_t 之后,可以通过多次调用 pthread_create 函数来创建多个线程。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐