【PTHREAD】线程属性

1. 线程属性结构

#  define __SIZEOF_PTHREAD_ATTR_T 56

union pthread_attr_t
{
  char __size[__SIZEOF_PTHREAD_ATTR_T];
  long int __align;
};

typedef union pthread_attr_t pthread_attr_t;

2. 初始化线程属性

int pthread_attr_init(pthread_attr_t *attr);
  • 以默认值的方式初始化线程属性对象。
  • 经过初始化后的线程属性对象可以使用不同的函数(pthread_attr_set*)设置对应的属性,最后将该属性用于pthread_create函数,用于创建具有指定属性的线程。
  • 调用该函数初始化一个已初始化的的线程属性对象,将导致不确定的行为。

3. 销毁线程属性

int pthread_attr_destroy(pthread_attr_t *attr);
  • 销毁一个线程属性对象
  • 线程属性对象销毁后,不影响使用该属性创建的线程对象
  • 已销毁的线程属性对象,可以使用pthread_attr_init重新初始化
  • 使用一个已销毁的线程属性对象,将导致不确定的行为

4. 线程属性之分离状态

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
  • 获取或设置线程属性对象中的线程分离状态。

  • 有两种状态值:

    • PTHREAD_CREATE_DETACHED
      使用该属性创建的线程,处于分离态
    • PTHREAD_CREATE_JOINABLE
      使用该属性创建的线程,处于关联态。默认值。
  • 拥有PTHREAD_CREATE_JOINABLE属性的线程,可通过pthread_detach修改为PTHREAD_CREATE_DETACHED。反之不可行。

5. 线程属性之栈保护区尺寸

int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize);
  • 如果该属性值大于零,则使用该属性创建的线程,在线程栈末尾多出一块至少guard size字节的保护区。
  • 如果该属性值等于零,则无线程栈保护区。
  • 默认保护大小与系统页面大小相同。
  • 如果使用pthread_attr_setstackpthread_attr_setstackaddr设置了线程属性对象的栈地址,则栈保护区大小被忽略。

6. 线程属性之调度继承

int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);
int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched);
  • 获取或设置线程线程对象中的继承线程调度属性。该属性指示使用该线程对象创建的线程是继承父线程的调度属性,还是线程属性对象中指定的调度属性。以下线程调度属性受该属性的影响:
    • 调度策略(pthread_attr_setschedpolicy
    • 调度优先级(pthread_attr_setschedparam
    • 调度作用域(pthread_attr_setscope
  • 继承调度属性支持以下值:
    • PTHREAD_INHERIT_SCHED
      继承父线程的调度属性。线程属性对象中的调度属性被忽略。默认值。
    • PTHREAD_EXPLICIT_SCHED
      使用该线程属性对象中的调度属性

7. 线程属性之调度策略

int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
  • 调度器是一个内核组件,该组件决定哪一个可运行的线程将运行。每一个线程都有一个相关的调度策略,一个静态的调度优先级。调度器根据系统上所有线程的调度策略和调度优先级做出调度决定。
  • 对于正常调度策略(SCHED_OTHER, SCHED_IDLE, SCHED_BATCH),调度优先级不用于调度决定,必须设置为0
  • 对于实时调度策略(SCHED_FIFO, SCHED_RR),调度优先级的范围[1, 99],值越大,优先级越高。
  • 对于特殊的调度策略,可以使用sched_get_priority_min(2)sched_get_priority_max(2)获取调度优先级的上下限
  • 该属性支持以下值:
    • SCHED_FIFO
      先入先出调度策略。该值仅能用于线程调度优先级高于零的线程。这意味着,一旦具有SCHED_FIFO属性的线程处于可运行状态,它总是立即抢占正在运行的具有正常调度策略的线程。
      • SCHED_RR
        循环调度策略。该策略是SCHED_FIFO策略的加强版。
      • SCHED_OTHER
        默认调度策略。此时线程调度优先级必须为0

8. 线程属性之调度参数

int pthread_attr_setschedparam(pthread_attr_t *attr,  const struct sched_param *param);
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);

struct sched_param {
    int sched_priority;     /* Scheduling priority */
};

9. 线程属性之调度作用域

int pthread_attr_setscope(pthread_attr_t *attr, int scope);
int pthread_attr_getscope(const pthread_attr_t *attr, int *scope);
  • PTHREAD_SCOPE_SYSTEM
    使用具有该属性的线程属性对象创建的线程将在系统级别上竞争资源。
  • PTHREAD_SCOPE_PROCESS
    使用具有该属性的线程属性对象创建的线程将在进程级别上竞争资源。

10. 线程属性之线程栈

// 栈地址与栈尺寸
int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize);

// 栈地址
int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr);
int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr);

// 栈尺寸
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize);

11. 案例:获取线程属性默认值

  • 源码

    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    
    int main(int argc, char const *argv[])
    {
        pthread_attr_t attr;
        pthread_attr_init(&attr);
    
        {
            int detech_state = 0;
            pthread_attr_getdetachstate(&attr, &detech_state);
            printf("default: detech state   = %s\n",
                   detech_state == PTHREAD_CREATE_DETACHED ? "PTHREAD_CREATE_DETACHED" :
                   detech_state == PTHREAD_CREATE_JOINABLE ? "PTHREAD_CREATE_JOINABLE" : "???");
        }
    
        {
            size_t guard_size = 0;
            pthread_attr_getguardsize(&attr, &guard_size);
            printf("default: guard size     = %lu\n", guard_size);
        }
    
        {
            int inherit_sched = 0;
            pthread_attr_getinheritsched(&attr, &inherit_sched);
            printf("default: inherit sched  = %s\n",
                   inherit_sched == PTHREAD_INHERIT_SCHED ? "PTHREAD_INHERIT_SCHED" :
                   inherit_sched == PTHREAD_INHERIT_SCHED ? "PTHREAD_INHERIT_SCHED" : "???");
        }
    
        {
            struct sched_param param;
            pthread_attr_getschedparam(&attr, &param);
            printf("default: sched_param    = %d\n", param.sched_priority);
        }
    
        {
            int sched_policy = 0;
            pthread_attr_getschedpolicy(&attr, &sched_policy);
            printf("default: sched policy   = %s\n",
                   sched_policy == SCHED_FIFO ? "SCHED_FIFO" :
                   sched_policy == SCHED_RR  ? "SCHED_RR" :
                   sched_policy == SCHED_OTHER ? "SCHED_OTHER" : "???");
        }
    
        {
            int scope = 0;
            pthread_attr_getscope(&attr, &scope);
            printf("default: scope          = %s\n",
                   scope == PTHREAD_SCOPE_SYSTEM ? "PTHREAD_SCOPE_SYSTEM" :
                   scope == PTHREAD_SCOPE_PROCESS ? "PTHREAD_SCOPE_PROCESS" : "???");
        }
    
        {
            void *stack_addr = NULL;
            size_t stack_size = 0;
            pthread_attr_getstack(&attr, &stack_addr, &stack_size);
            printf("default: stack_addr     = %p\n", stack_addr);
            printf("default: stack_size     = %lu\n", stack_size);
        }
    
        {
            void *stack_addr = NULL;
            pthread_attr_getstackaddr(&attr, &stack_addr); // 已弃用
            printf("default: stack_addr     = %p\n", stack_addr);
        }
    
        {
            size_t stack_size = 0;
            pthread_attr_getstacksize(&attr, &stack_size);
            printf("default: stack_size     = %lu\n", stack_size);
        }
        pthread_attr_destroy(&attr);
        exit(EXIT_SUCCESS);
    }
    
  • 输出

    default: detech state = PTHREAD_CREATE_JOINABLE
    default: guard size = 4096
    default: inherit sched = PTHREAD_INHERIT_SCHED
    default: sched_param = 0
    default: sched policy = SCHED_OTHER
    default: scope = PTHREAD_SCOPE_SYSTEM
    default: stack_addr = (nil)
    default: stack_size = 0
    default: stack_addr = (nil)
    default: stack_size = 8388608

12. CMakeLists.txt

cmake_minimum_required(VERSION 3.0.0)
project(pthread_examples VERSION 0.1.0 LANGUAGES C)

IF (CMAKE_BUILD_TYPE AND (CMAKE_BUILD_TYPE STREQUAL Debug))
    ADD_COMPILE_DEFINITIONS(DEBUG)
ENDIF()

# FindThreads Module
# 该模块用于确定系统的线程库。
# 如果查找到线程库,该模块定义目标:Threads::Threads
# 定义以下变量:
#   Threads_FOUND
#       如果有支持的线程库被查找到
#   CMAKE_THREAD_LIBS_INIT
#       将要使用的线程库。如果该线程库是由系统库提供的,并且不需要特殊标志来使用它们,则可能为空
#   CMAKE_USE_WIN32_THREADS_INIT
#       如果查找到的库是WIN32,则返回1,否则返回0
#   CMAKE_USE_PTHREADS_INIT
#       指示找到的库是否为pthread兼容库
#   CMAKE_HP_PTHREADS_INIT
#       指示找到的库是否是HP线程库
SET(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
IF (Threads_FOUND)
    message(STATUS ======================================================)
    message(STATUS "CMAKE_THREAD_LIBS_INIT       : ${CMAKE_THREAD_LIBS_INIT}")
    message(STATUS "CMAKE_USE_WIN32_THREADS_INIT : ${CMAKE_USE_WIN32_THREADS_INIT}")
    message(STATUS "CMAKE_USE_PTHREADS_INIT      : ${CMAKE_USE_PTHREADS_INIT}")
    message(STATUS "CMAKE_HP_PTHREADS_INIT       : ${CMAKE_HP_PTHREADS_INIT}")
    message(STATUS ======================================================)
    add_definitions     ( ${EIGEN3_DEFINITIONS} )
    include_directories ( ${EIGEN3_INCLUDE_DIRS} )
ENDIF()

# 链接线程库
link_libraries(Threads::Threads)

# 创建线程
add_executable(pthread_create main.c)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhy29563

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值