Linux线程属性及优先级设置分类

线程的属性由pthread_attr_t 结构类型表示。
在使用pthread_attr_t 之前,需要调用pthread_attr_init 对其初始化。pthread_attr_init 为
pthread_attr_t 结构里面的各个属性设置默认值。程序可以修改这些值,定制线程的各个属
性。在使用完pthread_attr_t 后,需要调用pthread_attr_destroy,完成一些清理工作。
[cpp]
int pthread_attr_init ( pthread_attr_t *attr );
int pthread_attr_destroy ( pthread_attr_t *attr );
[/cpp]
无需了解pthread_attr_t 的具体结构,POSIX.1 指定了一系列方法获取和设置
pthread_attr_t 结构里面的各个属性。
(1)分离状态(detached state):若线程终止时,线程处于分离状态,系统不保留线程终
止的状态。当不需要线程的终止状态时,可以分离线程(调用pthread_detach 函数)。若在
线程创建的时候,就已经知道以后不需要使用线程的终止状态时,可以在线程创建属性里面
指定该状态,那么线程一开始就处于分离状态。通过下面两个函数,设置和获取线程的分离
属性。
[cpp]
int pthread_attr_getdetachstate ( const pthread_attr_t *attr, int *state );
int pthread_attr_setdetachstate ( pthread_attr_t *attr, int state );
[/cpp]
该属性的可选值有:PTHREAD_CREATE_DETACHED、
PTHREAD_CREATE_JOINABLE。
(2)栈地址(stack address):POSIX.1 定义了两个常量
_POSIX_THREAD_ATTR_STACKADDR 和_POSIX_THREAD_ATTR_STACKSIZE 检测系统
是否支持栈属性。当然也可以给sysconf 函数传递_SC_THREAD_ATTR_STACKADDR 或
_SC_THREAD_ATTR_STACKSIZE 来进行检测。当进程栈地址空间不够用时,指定新建线
程使用由malloc 分配的空间作为自己的栈空间。通过pthread_attr_setstackaddr 和
pthread_attr_getstackaddr 两个函数分别设置和获取线程的栈地址。传给
pthread_attr_setstackaddr 函数的地址是缓冲区的低地址(不一定是栈的开始地址,栈可能从
高地址往低地址增长)。
[cpp]
int pthread_attr_getstackaddr ( const pthread_attr_t *attr, void **addr );
int pthread_attr_setstackaddr ( pthread_attr_t *attr, void *addr );
[/cpp]
(3)栈大小(stack size):当系统中有很多线程时,可能需要减小每个线程栈的默认大
小,防止进程的地址空间不够用;当线程调用的函数会分配很大的局部变量或者函数调用层
次很深时,可能需要增大线程栈的默认大小。函数pthread_attr_getstacksize 和
pthread_attr_setstacksize 被提供。
[cpp]
int pthread_attr_getstacksize ( const pthread_attr_t *attr, size_t *size );
int pthread_attr_setstacksize ( pthread_attr_t *attr, size_t size );
[/cpp]
函数pthread_attr_getstack 和pthread_attr_setstack 函数可以同时操作栈地址和栈大小两个
属性:
[cpp]
int pthread_attr_getstack ( const pthread_attr_t *attr, void **stackaddr, size_t *size );
int pthread_attr_setstack ( pthread_attr_t *attr, void *stackaddr, size_t size );
[/cpp]
(4)栈保护区大小(stack guard size):在线程栈顶留出一段空间,防止栈溢出。当栈指
针进入这段保护区时,系统会发出错误,通常是发送信号给线程。该属性默认值是
PAGESIZE 大小,该属性被设置时,系统会自动将该属性大小补齐为页大小的整数倍。当改
变栈地址属性时,栈保护区大小通常清零。
[cpp]
int pthread_attr_getguardsize ( const pthread_attr_t *attr, size_t *guardsize );
int pthread_attr_setguardsize ( pthread_attr_t *attr, size_t guardsize );
[/cpp]
(5)线程优先级(priority):新线程的优先级为 0。
[cpp]
int pthread_attr_getschedparam(const pthread_attr_t *restrict attr, struct sched_param *restrict
param);
int pthread_attr_setschedparam(pthread_attr_t *restrict attr, const struct sched_param *restrict
param);
[/cpp]
(6)继承父进程优先级(inheritsched):新线程不继承父线程调度优先级
(PTHREAD_EXPLICIT_SCHED)
(7)调度策略(schedpolicy):新线程使用 SCHED_OTHER 调度策略。线程一旦开始运
行,直到被抢占或者直到线程阻塞或停止为止。
[cpp]
int pthread_attr_setschedpolicy(pthread_attr_t* attr, int policy)
int pthread_attr_setschedparam (pthread_attr_t* attr, struct sched_param* param);
[/cpp]
(8)争用范围(scope)建立线程的争用范围(PTHREAD_SCOPE_SYSTEM 或
PTHREAD_SCOPE_PROCESS)。使用 PTHREAD_SCOPE_SYSTEM 时,此线程将与系统
中的所有线程进行竞争。使用 PTHREAD_SCOPE_PROCESS 时,此线程将与进程中的其他
线程进行竞争。这个又叫绑定状态,PTHREAD_SCOPE_SYSTEM(绑定的)和
PTHREAD_SCOPE_PROCESS(非绑定的)。具有不同范围状态的线程可以在同一个系统甚
至同一个进程中共存。进程范围只允许这种线程与同一进程中的其他线程争用资源,而系统
范围则允许此类线程与系统内的其他所有线程争用资源。对于Solaris 系统,实际上,从
Solaris 9 发行版开始,系统就不再区分这两个范围。
[cpp]
int pthread_attr_getscope(const pthread_attr_t *restrict attr, int *restrict contentionscope);
int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope);
[/cpp]
(9)线程并行级别(concurrency)应用程序使用 pthread_setconcurrency() 通知系统其所
需的并发级别。
[cpp]
int pthread_getconcurrency(void);
int pthread_setconcurrency(int new_level);
[/cpp]
POSIX 标准指定了三种调度策略:先入先出策略 (SCHED_FIFO)、循环策略 (SCHED_RR)
和自定义策略 (SCHED_OTHER)。SCHED_FIFO 是基于队列的调度程序,对于每个优先级
都会使用不同的队列。SCHED_RR 与 FIFO 相似,不同的是前者的每个线程都有一个执行
时间配额。
SCHED_FIFO 和 SCHED_RR 是对 POSIX Realtime 的扩展。SCHED_OTHER 是缺省的调
度策略。
POSIX 标准指定了三种调度策略:先入先出策略 (SCHED_FIFO)、循环策略
(SCHED_RR) 和自定义策略 (SCHED_OTHER)。SCHED_FIFO 是基于队列的调度程序,对
于每个优先级都会使用不同的队列。SCHED_RR 与 FIFO 相似,不同的是前者的每个线程
都有一个执行时间配额。
SCHED_FIFO
如果调用进程具有有效的用户 ID 0,则争用范围为系统 (PTHREAD_SCOPE_SYSTEM) 的
先入先出线程属于实时 (RT) 调度类。如果这些线程未被优先级更高的线程抢占,则会继续
处理该线程,直到该线程放弃或阻塞为止。对于具有进程争用范围
(PTHREAD_SCOPE_PROCESS)) 的线程或其调用进程没有有效用户 ID 0 的线程,请使用
SCHED_FIFO。SCHED_FIFO 基于 TS 调度类。
SCHED_RR
如果调用进程具有有效的用户 ID 0,则争用范围为系统 (PTHREAD_SCOPE_SYSTEM))
的循环线程属于实时 (RT) 调度类。如果这些线程未被优先级更高的线程抢占,并且这些线
程没有放弃或阻塞,则在系统确定的时间段内将一直执行这些线程。对于具有进程争用范围
(PTHREAD_SCOPE_PROCESS) 的线程,请使用 SCHED_RR(基于 TS 调度类)。此外,
这些线程的调用进程没有有效的用户 ID 0。
例:创建优先级为50 的线程。
pthread_attr_t attr;
struct sched_param param;
pthread_attr_init(&attr);
pthread_attr_setschedpolicy(&attr, SCHED_RR);
param.sched_priority = 50;
pthread_attr_setschedparam(&attr, &param);
pthread_create(&threadid, &attr, &threadfunc, NULL);
pthread_attr_destroy(&attr);
<think>我们被要求设置Linux系统线程优先级。根据引用[3],我们可以使用线程调度相关的函数来设置优先级。具体来说,有两个函数:pthread_setschedparam(用于设置线程的调度策略和优先级)和pthread_attr_setschedparam(用于设置线程属性的调度参数,以便在创建线程时使用)。此外,我们还需要了解struct sched_param结构,它包含一个整数成员__sched_priority,表示要设置线程优先级。 在Linux中,线程优先级与调度策略紧密相关。常见的调度策略有: - SCHED_OTHER(标准循环分时策略,优先级固定为0,不可设置优先级) - SCHED_FIFO(先进先出实时策略,优先级范围1-99,数值越大优先级越高) - SCHED_RR(轮转实时策略,优先级范围1-99) 注意:只有具有CAP_SYS_NICE能力的进程(通常是root用户)才能设置实时调度策略(SCHED_FIFO或SCHED_RR)和提高优先级。 步骤: 1. 确定要使用的调度策略(如SCHED_FIFO)。 2. 设置优先级值(在1到99之间,对于实时策略)。 3. 使用pthread_setschedparam函数设置运行中线程优先级,或者使用pthread_attr_setschedparam设置线程属性,然后创建线程。 示例代码: ```c #include <pthread.h> #include <sched.h> void set_thread_priority(pthread_t thread, int policy, int priority) { struct sched_param param; param.sched_priority = priority; // 设置线程的调度策略和优先级 if (pthread_setschedparam(thread, policy, &param) != 0) { // 错误处理 } } // 或者在创建线程设置 void create_high_priority_thread() { pthread_attr_t attr; struct sched_param param; pthread_t thread; pthread_attr_init(&attr); // 设置调度策略为SCHED_FIFO pthread_attr_setschedpolicy(&attr, SCHED_FIFO); param.sched_priority = 50; // 设置优先级为50 pthread_attr_setschedparam(&attr, &param); // 必须设置线程属性为显式设置调度策略和参数 pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); pthread_create(&thread, &attr, thread_function, NULL); pthread_attr_destroy(&attr); } ``` 另外,引用[1]提到Java线程优先级Linux nice值的映射关系,但请注意,Java线程优先级(1-10)映射到Linux优先级(nice值)并不是一一对应实时优先级,而是映射到普通进程的nice值(-20到19,但Java映射为1-10对应到nice值-20到19的某个子集)。如果我们需要设置实时优先级,必须使用上述的实时调度策略,而不是通过nice值。 此外,引用[2]描述了在迁移任务时的一些内核操作,但与我们设置线程优先级没有直接关系。引用[4]提到setuid,这涉及到权限问题,因为设置实时优先级需要特权,所以程序可能需要以root运行,或者通过setuid赋予程序相应的权限(但要注意安全风险)。引用[5]与问题无关。 因此,总结步骤如下: 1. 确定调度策略(实时策略需要root权限)。 2. 设置优先级(实时策略下1-99,普通策略下只能是0)。 3. 使用pthread_setschedparam或线程属性设置。 注意:在设置实时优先级时,要确保程序以root权限运行,或者程序文件被设置了setuid(如引用[4]所示,但通常不推荐,因为存在安全风险)。 最后,我们生成相关问题: 1. 如何在不使用root权限的情况下设置实时线程优先级? 2. 不同调度策略(SCHED_FIFO, SCHED_RR, SCHED_OTHER)之间有什么区别? 3. 如何查看一个线程当前的调度策略和优先级?</think>### 如何在 Linux设置线程优先级Linux设置线程优先级主要通过 POSIX 线程 API 实现,涉及调度策略和优先级参数。以下是详细步骤: #### 一、核心方法 1. **使用 `pthread_setschedparam` 函数** ```c #include <pthread.h> #include <sched.h> void set_thread_priority(pthread_t thread, int policy, int priority) { struct sched_param param; param.sched_priority = priority; // 设置优先级值 // 应用调度策略和优先级 if (pthread_setschedparam(thread, policy, &param) != 0) { perror("pthread_setschedparam failed"); } } ``` - **policy**:调度策略 - `SCHED_FIFO`:先进先出(实时策略,优先级 1-99) - `SCHED_RR`:轮转调度(实时策略,优先级 1-99) - `SCHED_OTHER`:标准分时策略(优先级为 0) - **priority**:优先级值(实时策略下范围 1-99,数值越大优先级越高)[^3] 2. **创建线程时指定优先级** ```c pthread_attr_t attr; struct sched_param param; pthread_attr_init(&attr); pthread_attr_setschedpolicy(&attr, SCHED_FIFO); // 设置调度策略 param.sched_priority = 80; // 设置优先级 (1-99) pthread_attr_setschedparam(&attr, &param); pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); // 禁用继承 pthread_t thread; pthread_create(&thread, &attr, thread_function, NULL); ``` #### 二、关键注意事项 1. **权限要求** - 设置实时优先级(`SCHED_FIFO`/`SCHED_RR`)需要 **root 权限** 或 `CAP_SYS_NICE` 能力 - 可通过 `setuid` 或 `sudo` 提权(参考 [^4]): ```bash sudo chmod +s /path/to/your_program # 设置 setuid ``` 2. **优先级映射** - 不同语言优先级映射不同(如 Java 线程优先级 1-10 映射到 Linux nice 值 -20 到 19)[^1]: | Java 优先级 | Linux nice 值 | |------------|--------------| | 1 | 42 | | 5 | 0 | | 10 | -5 | 3. **资源冲突避免** - CPU 绑定:使用 `sched_setaffinity()` 限制线程在特定核心运行 - 内存锁定:`mlockall()` 防止页错误(对实时线程关键) #### 三、完整示例 ```c #include <pthread.h> #include <sched.h> #include <stdio.h> void* thread_func(void* arg) { // 实时任务代码 return NULL; } int main() { pthread_attr_t attr; pthread_t thread; // 初始化线程属性 pthread_attr_init(&attr); // 设置调度策略为 FIFO pthread_attr_setschedpolicy(&attr, SCHED_FIFO); // 设置优先级为 90 (较高优先级) struct sched_param param = { .sched_priority = 90 }; pthread_attr_setschedparam(&attr, &param); // 显式声明不使用继承 pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); // 创建线程 pthread_create(&thread, &attr, thread_func, NULL); // 等待线程结束 pthread_join(thread, NULL); return 0; } ``` 编译运行: ```bash gcc -o rt_thread rt_thread.c -lpthread sudo ./rt_thread # 需要 root 权限 ``` #### 四、验证优先级 ```bash # 查看线程优先级 ps -eLo pid,tid,cls,rtprio,cmd | grep <thread_name> # 输出示例: # PID TID CLS RTPRIO CMD # 12345 12346 FF 90 ./rt_thread ``` - **CLS**:调度类(TS=分时, FF=FIFO, RR=轮转) - **RTPRIO**:实时优先级(1-99) > **安全警告**:错误使用实时优先级可能导致系统锁定(如 `SCHED_FIFO` 线程无限循环),建议在开发环境中充分测试[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值