--------------------------------------------------
author: hjjdebug
date: 2024年 03月 12日 星期二 12:43:38 CST
decription: 创建线程时指定线程属性,调整线程优先级
--------------------------------------------------
普通线程,根本没有优先级,最多只能调整一下nice值,想把线程
调整为实时线程,并设定线程优先级,需要先把线程策略调整为
FIFO(first in firt out)或RR(rotate robin), 然后可设置优先级值
完整代码如下,注意点都在代码注释中.
$ cat main.cpp
#include <stdio.h> // for printf, perror, NULL
#include <unistd.h> // for getpid, gettid, sleep
#include <pthread.h> // for pthread_attr_getschedparam
#include <sched.h> // for SCHED_FIFO, sched_priority
void *thread_func(void *arg) {
(void) arg;
printf("I'm a new thread.,threadID:%d\n",gettid());
while(1)
{
//这里子线程不退出,方便我们用命令查看其优先A级
//其命令为ps -p <pid> -T -o tid,comm,rtprio
// rtprio 中 - 表示非实时线程, 有值表示实时线程
sleep(1);
}
pthread_exit(NULL);
}
int main() {
printf("I'm parent thread, pid is %d\n",getpid());
// 初始化线程属性
pthread_attr_t attr;
pthread_attr_init(&attr);
// 设置继承调度策略
pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
// 设置线程调度策略为SCHED_FIFO,其优先级范围为(1-99)
pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
// 设置线程调度参数,优先级设为80
struct sched_param param;
param.sched_priority = 80;
pthread_attr_setschedparam(&attr, ¶m);
// 创建新线程并运行
pthread_t thread_id;
int ret;
//用attr 来创建thread
if ((ret=pthread_create(&thread_id, &attr, thread_func, NULL)) != 0) {
printf("ret:%d\n",ret); //非root 用户会返回1(EPERM), 权限不够
perror("pthread_create error");
return 1;
}
// 获取线程调度策略和参数, 下面代码只是查看一下我们的attr 是否设置对了
int policy;
//用来检查attr 是否是实时的,SCHED_FIFO,SCHED_RR都是实时的
ret=pthread_attr_getschedpolicy(&attr, &policy);
if(ret!=0) printf("error get policy\n");
// 输出线程调度策略和参数
printf("Thread policy: ");
switch (policy) {
case SCHED_FIFO:
printf("FIFO\n");
break;
case SCHED_RR:
printf("RR\n");
break;
case SCHED_OTHER:
printf("OTHER\n");
break;
default:
printf("UNKNOWN\n");
}
// 检查attr 设定的优先级
ret=pthread_attr_getschedparam(&attr, ¶m);
if(ret!=0) printf("error get parameter\n");
printf("Thread priority: %d\n", param.sched_priority);
// 等待子线程结束
if (pthread_join(thread_id, NULL) != 0) { //子线程没有退出,主线程也不会退,方便我们观察线程属性!!
perror("pthread_join error");
return 1;
}
return 0;
}
执行结果: 需要超级用户权限, 请用root 或sudo 命令.
./thread_attr
I'm parent thread, pid is 8996
Thread policy: FIFO
Thread priority: 80
I'm a new thread.,threadID:8997
程序按我们的要求在运行, 此时我们用命令行查询其线程优先级.
$ ps -p 8996 -T -o tid,comm,rtprio
TID COMMAND RTPRIO
8996 thread_attr -
8997 thread_attr 80
可见线程8997 确实是实时线程, 优先级80
如果你想查看当前所有的实时线程.用下面命令: 只看rtprio有值的即可.
$ ps -e -T -o tid,comm,rtprio | grep -v -
补充:
代码在centos7 上运行失败,虽然是root, 但创建线程还是返回1, EPERM, ubuntu 上可以,没有出错!!
进一步查原因, 在stackoverflow 上找到答案.
可参考以下连接
https://stackoverflow.com/questions/9313428/getting-eperm-when-calling-pthread-create-for-sched-fifo-thread-as-root-on-lino
它说,
kernel/sched/core.c 中返回的错误
if (user) {
if (rt_bandwidth_enabled() && rt_policy(policy) && task_group(p)->rt_bandwidth.rt_runtime == 0 && !task_group_is_autogroup(task_group(p)))
{
task_rq_unlock(rq, p, &flags);
return -EPERM;
}
解决办法:
在centos 上, 需要把执行shell 的 pid 值加入到 /sys/fs/cgroup/cpu/tasks
即在你的shell 下执行
# echo $$ > /sys/fs/cgroup/cpu/tasks
再执行就不报错了.
实验成功了,确实这样可以解决问题.
但手工把shell 的pid 加入到一个控制组中的tasks 中,也太变态了, 干脆不用了!