Linux 线程优先级
概述
概述内容
常见的运用场景:
- 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),而且用完了它的时间片. |
这张图表示的是内核中的优先级,分为两段。
前面的数值 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, ¶m); // 设置当前进程
11 pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m); // 设置当前线程
优先级测试代码
#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;
}