> 文章列表 > Linux 线程优先级

Linux 线程优先级

Linux 线程优先级

目录标题

  • 概述
  • Linux进程调度的三种策略
  • Linux 线程优先级
    • 对于实时任务
    • 对于普通任务
    • top中的PR和NI
    • 其他说明
  • 代码示例
    • 设置为实时进程
    • 优先级测试代码

概述

概述内容


常见的运用场景

  • 1
  • 2;
  • 3;

Linux进程调度的三种策略

  • SCHED_OTHER,分时调度策略
    该策略是是默认的Linux分时调度(time-sharing scheduling)策略,它是Linux线程默认的调度策略。SCHED_OTHER策略的静态优先级总是为0,对于该策略列表上的线程,调度器是基于动态优先级(dynamic priority)来调度的,动态优先级是跟nice中相关(nice值可以由接口nice, setpriority,sched_setattr来设置),该值会随着线程的运行时间而动态改变,以确保所有具有SCHED_OTHER策略的线程公平运行
  • SCHED_FIFO,实时调度策略,先到先服务。
    根据进程的优先级进行调度,一旦抢占到 CPU 则一直运行,直达自己主动放弃或被被更高优先级的进程抢占;
  • SCHED_RR,实时调度策略,时间片轮转
    在 SCHED_FIFO 的基础上,加上了时间片的概念。当一个进程抢占到 CPU 之后,运行到一定的时间后,调度器会把这个进程放在 CPU 中,当前优先级进程队列的末尾,然后选择另一个相同优先级的进程来执行;

Linux 线程优先级

进程 调度策略 优先级 说明
普通进程 SCHED_OTHER或SCHED_NORMAL 100-139 这个区间的优先级又称为静态优先级,不会随着时间而改变,内核不会修改它,只能通过系统调用nice去修改,静态优先级数值越大,进程的优先级越小,分配的基时间量就越少。普通进程几乎是无法分到时间片的(只能分到5%的CPU时间)。static priority=nice+20+MAX_RT_PRIO,nice值[-20,19],MAX_RT_PRIO默认为100,这样做的好处是,任何内核态进程优先级都大于用户态的进程.
实时进程 SCHED_FIFO或SCHED_RR 0-99 只有在下述事件之一发生时,实时进程才会被另外一个进程取代 1. 进程被另外一个具有更高实时优先级的实时进程抢占2. 进程执行了阻塞操作并进入睡眠3. 进程停止(处于TASK_STOPPED 或TASK_TRACED状态)或被杀死4. 进程通过调用系统调用sched_yield(),自愿放弃CPU5. 进程基于时间片轮转的实时进程(SCHED_RR),而且用完了它的时间片.

Linux 线程优先级

这张图表示的是内核中的优先级,分为两段。
前面的数值 0-99 是实时任务,后面的数值 100-139 是普通任务。
数值越低,代表这个任务的优先级越高。
以上是从内核角度来看的优先级。


我们在应用层创建线程的时候,设置了一个优先级数值,这是从应用层角度来看的优先级数值。
但是内核并不会直接使用应用层设置的这个数值,而是经过了一定的运算,才得到内核中所使用的优先级数值(0 ~ 139)。

对于实时任务

我们在创建线程的时候,可以通过下面这样的方式设置优先级数值(0 ~ 99):

struct sched_param param;
param.__sched_priority = xxx;

当创建线程函数进入内核层面的时候,内核通过下面这个公式来计算真正的优先级数值:
kernel priority = 100 - 1 - param.__sched_priority

如果应用层传入数值 0,那么在内核中优先级数值就是 99(100 - 1 - 0 = 99),在所有实时任务中,它的优先级是最低的。
如果应用层传输数值 99,那么在内核中优先级数值就是 0(100 - 1 - 99 = 0),在所有实时任务中,它的优先级是最高的。
因此,从应用层的角度看,传输人优先级数值越大,线程的优先级就越高;数值越小,优先级就越低。
与内核角度是完全相反的!

对于普通任务

调整普通任务的优先级,是通过 nice 值来实现的,内核中也有一个公式来把应用层传入的 nice 值,转成内核角度的优先级数值:
kernel prifoity = 100 + 20 + nice
nice 的合法数值是:-20 ~ 19
如果应用层设置线程 nice 数值为 -20,那么在内核中优先级数值就是 100(100 + 20 + (-20) = 100),在所有的普通任务中,它的优先级是最高的。
如果应用层设置线程 nice 数值为 19,那么在内核中优先级数值就是 139(100 +20 +19 = 139),在所有的普通任务中,它的优先级是最低的。
因此,从应用层的角度看,传输人优先级数值越小,线程的优先级就越高;数值越大,优先级就越低。
与内核角度是完全相同的!

top中的PR和NI

top命令中pri的计算方法 说明
普通进程 top_pr=static_priority-100 static_priority取值是[100,139],所以top_pri取值是[0,39]
实时进程 top_pri=-1-real_time_priority chrt命令就是修改实时进程的优先级,比如给进程12345分配优先级为93,chrt -p 93 12345,则top命令pri值显示的是-94。有的实时进程的pri值显示的是rt,没有具体显示数值

其他说明

对于多核处理器,分布不同核时,调度策略、优先级,都不起作用!(准确的说:调度策略和优先级,在线程所在的那个 CPU 中是起作用的)

代码示例

设置为实时进程

 1 #include <stdio.h>2 #include <stdlib.h>3 #include <pthread.h>4 #include <sched.h>5 6 7 pid_t pid = getpid();8 struct sched_param param;9 param.sched_priority = sched_get_priority_max(SCHED_FIFO);   // 也可用SCHED_RR
10 sched_setscheduler(pid, SCHED_RR, &param);                   // 设置当前进程
11 pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);   // 设置当前线程

优先级测试代码

#include <stdio.h>
#include <pthread.h>
#include <sched.h>
#include <assert.h>static int get_thread_policy(pthread_attr_t *attr)
{int policy;int rs = pthread_attr_getschedpolicy(attr,&policy);assert(rs==0);switch(policy)
{case SCHED_FIFO:printf("policy=SCHED_FIFO\\n");break;case SCHED_RR:printf("policy=SCHED_RR\\n");break;case SCHED_OTHER:printf("policy=SCHED_OTHER\\n");break;default:printf("policy=UNKNOWN\\n");break;}return policy;
}static void show_thread_priority(pthread_attr_t *attr,int policy)
{int priority = sched_get_priority_max(policy);assert(priority != -1);printf("max_priority=%d\\n",priority);priority= sched_get_priority_min(policy);assert(priority != -1);printf("min_priority=%d\\n",priority);
}static int get_thread_priority(pthread_attr_t *attr)
{struct sched_param param;int rs = pthread_attr_getschedparam(attr,¶m);assert(rs == 0);printf("priority=%d\\n",param.__sched_priority);return param.__sched_priority;
}static void set_thread_policy(pthread_attr_t *attr,int policy)
{int rs = pthread_attr_setschedpolicy(attr,policy);assert(rs==0);
}int main(void)
{pthread_attr_t attr;int rs;rs = pthread_attr_init(&attr);assert(rs==0);int policy = get_thread_policy(&attr);printf("Show current configuration of priority\\n");get_thread_policy(&attr);show_thread_priority(&attr,policy);printf("show SCHED_FIFO of priority\\n");show_thread_priority(&attr,SCHED_FIFO);printf("show SCHED_RR of priority\\n");show_thread_priority(&attr,SCHED_RR);printf("show priority of current thread\\n");get_thread_priority(&attr);printf("Set thread policy\\n");printf("set SCHED_FIFO policy\\n");set_thread_policy(&attr,SCHED_FIFO);get_thread_policy(&attr);get_thread_priority(&attr);printf("set SCHED_RR policy\\n");set_thread_policy(&attr,SCHED_RR);get_thread_policy(&attr);printf("Restore current policy\\n");set_thread_policy(&attr,policy);get_thread_priority(&attr);rs = pthread_attr_destroy(&attr);assert(rs==0);return 0;
}