【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_setstack
或pthread_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, ¶m); 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)