linux线程调度策略

您所在的位置:网站首页 怎样设置线程的优先级 linux线程调度策略

linux线程调度策略

2023-10-17 16:59| 来源: 网络整理| 查看: 265

linux线程调度策略

这是一篇非常好的关于线程调度的资料,翻译自shed

目录linux线程调度策略Scheduling policiesSCHED_FIFO: First in-first out scheduling(实时线程)SCHED_RR: Round-robin scheduling(轮询调度)SCHED_DEADLINE: Sporadic task model deadline schedulingSCHED_OTHER: Default Linux time-sharing scheduling(默认策略)The nice valueSCHED_BATCH: Scheduling batch processesSCHED_IDLE: Scheduling very low priority jobsResetting scheduling policy for child processesPrivileges and resource limitsLimiting the CPU usage of real-time and deadline processes(限制实时进程或deadline进程)Response timeMiscellaneousThe autogroup featureThe nice value and group schedulingReal-time features in the mainline Linux kernelTIPS:参考

从Linux 2.6.23开始,默认的调度器为CFS,即"完全公平调度器"(Completely Fair Scheduler)。CFS调度器取代了之前的"O(1)"调度器。

CFS的实现细节可以参见sched-design-CFS。cgroup的CPU调度也属于CFS扩展的一部分。

Scheduling policies

内核模块使用调度器来决定下一个CPU时钟周期执行的线程。每个线程都包含一个调度策略以及一个静态的调度优先级sched_priority,调度器根据系统上所有线程的调度策略和静态优先级来决定如何进行调度。

对于使用普通调度策略(SCHED_OTHER, SCHED_IDLE, SCHED_BATCH)的线程来说,sched_priority并不会影响调度结果,且必须设置为0。

对于使用实时策略(SCHED_FIFO,SCHED_RR)的进程,其sched_priority取值为1到99(1为最低值)。实时线程的调度优先级总是高于普通线程。注:POSIX.1的系统在实现中,会要求实时调度策略有32个优先级设置,因此,为了可移植性,可以使用sched_get_priority_min和sched_get_priority_max来查找调度策略所支持的优先级范围。

调度器会为每个sched_priority值维护一个可运行的线程列表。调度器通过查看非空且静态优先级最高的列表,并选择该列表首部的元素作为下一个运行的线程。

线程的调度策略决定了如何根据静态优先级来将一个线程插入到同静态优先级的线程列表(list of runnable threads)中,以及如何在该列表中调整线程的位置。

所有的调度都具有抢占性:如果一个具有更高静态优先级的线程准备运行,当前运行的线程会被抢占并返回到其静态优先级对应的等待列表中。调度策略仅根据具有相同静态优先级的可运行线程列表来决定调度顺序。

进程调度中使用了2个队列:进程一开始会进入ready队列等待调度;当进程执行中遇到I/O阻塞,等待子进程结束或软中断等原因会进入wait队列,等阻塞结束后会返回到ready队列

SCHED_FIFO: First in-first out scheduling(实时线程)

SCHED_FIFO仅适用于静态优先级大于0的线程,即当一个SCHED_FIFO的线程变为可运行(runnable)状态时,它会立即抢占所有当前运行的SCHED_OTHER, SCHED_BATCH或SCHED_IDLE 线程。SCHED_FIFO不使用时间片进行调度,所有使用SCHED_FIFO调度策略的线程应该遵守如下规则:

当一个运行中的SCHED_FIFO线程被其他有更高优先级的线程抢占后,该线程会返回到其优先级对应的列表的首部,当所有更高优先级的线程阻塞后,该线程将会立即恢复运行;

当一个阻塞的SCHED_FIFO 线程变为可运行状态时,该线程会返回到其优先级对应的列表末尾;

如果调用 sched_setscheduler(2),sched_setparam(2),sched_setattr(2),pthread_setschedparam(3),pthread_setschedprio(3) (通过pid)修改了正在运行或可运行状态的SCHED_FIFO线程的优先级时,该线程在列表中的位置取决于优先级的变动:

如果线程优先级增加了,它将会放置到新优先级对应的列表末尾,同时可能抢占正在运行的具有相同优先级的线程;

如果线程优先级没变,其在运行列表中的位置不变;

如果线程优先级减小了,它将会放置到新优先级对应的列表的前面。

根据POSIX.1-2008,通过非 pthread_setschedprio(3)方式来修改线程的优先级,可能会导致其放置到对应优先级列表的末尾。

调用了sched_yield(2) (用于释放CPU)的线程将会放置到列表末尾

SCHED_FIFO 线程将会一直运行,直到被更高优先级的线程抢占,或调用了sched_yield(2) 。

SCHED_RR: Round-robin scheduling(轮询调度)

SCHED_RR对SCHED_FIFO做了简单增强。除每个线程仅允许运行在一个最大时间段下外,SCHED_FIFO中的所有规则都适用于SCHED_RR。如果一个SCHED_RR线程已经运行了等于或大于该最大时间段时,该线程会被放置到其优先级列表的末尾。当一个SCHED_RR线程被更高优先级的线程抢占,并在后续恢复运行后,会在先前未过期的时间段下运行。最大时间段可以通过sched_rr_get_interval(2)获得。

SCHED_DEADLINE: Sporadic task model deadline scheduling

3.14版本之后的Linux提供了一个新的调度策略SCHED_DEADLINE。该策略结合了GEDF(Global Earliest Deadline First)和 CBS (Constant Bandwidth Server)。必须通sched_setattr(2)和sched_getattr(2)来设置和获取该策略。

一个Sporadic task被定义为一系列任务,且每个任务每次仅激活一次。每个任务都有一个relative deadline(该任务应该在该相对时间前停止运行),以及一个computation time(执行该任务需要的CPU时间,对应下图的comp. time)。一个新的任务开始执行时会唤醒(wakeup)一个Sporadic task,该时间点被称为arrival time,start time为一个任务开始执行的时间,absolute deadline(绝对截止时间)为arrival time加上relative deadline的时间点。

arrival/wakeup absolute deadline | start time | | | | v v v -----x--------xooooooooooooooooo--------x--------x--- || || ||

当使用sched_setattr(2)给一个线程设置SCHED_DEADLINE 策略时,可以设置3个参数:Runtime, Dead‐line和Period,对于上面提到的场景来说,通常的做法是将Runtime设置为大于平均计算时间的值(或更坏的场景下,设置为硬实时任务的执行时间);将Deadline设置为对应的dead-line,将Period设置为任务的周期,此时对于SCHED_DEADLINE的调度如下:

Runtime对应上图中的comp.time,Dead-line对应上图的relative deadline

arrival/wakeup absolute deadline | start time | | | | v v v -----x--------xooooooooooooooooo--------x--------x--- || || ||

3个deadline调度参数对应sched_attr结构体中的sched_run‐time, sched_deadline, 和sched_period字段,参见sched_setattr(2)。这些字段的单位为纳秒。如果sched_period的值为0,则它与sched_deadline相同。

内核要求:

sched_runtime runnable_avg : 8 .tg->cfs_bandwidth.timer_active: 0 .throttled : 0 .throttle_count : 0 .se->exec_start : 7432565479.124290 .se->vruntime : 560032308.234830 .se->sum_exec_runtime : 7762399.141979 .se->load.weight : 2 .se->avg.runnable_avg_sum : 147 .se->avg.runnable_avg_period : 47729 .se->avg.load_avg_contrib : 1 .se->avg.decay_count : 7088246803

可以在/proc/$pid/sched中查看特定进程的调度情况

# cat sched docker-proxy-cu (77992, #threads: 8) ------------------------------------------------------------------- se.exec_start : 7179182946.125343 se.vruntime : 1843988.364695 se.sum_exec_runtime : 6.017643 se.nr_migrations : 2 nr_switches : 6 nr_voluntary_switches : 4 nr_involuntary_switches : 2 se.load.weight : 1024 policy : 0 prio : 120 clock-delta : 34 mm->numa_scan_seq : 0 numa_migrations, 0 numa_faults_memory, 0, 0, 1, 0, -1 numa_faults_memory, 1, 0, 0, 0, -1

一个线程可以通过系统分配的时间片在各个CPU core上允许,但一个线程不能同时在多个core上运行。如果一个系统有N个core,那么可以同时在这些core上允许N个线程。将CPU core上线程切换到另外一个线程时,会涉及到上下文切换,上下文切换时需要保存PCB中的CPU寄存器信息,进程状态以及内存管理等信息,在进程恢复时还原这些信息。

可以通过/proc/$pid/status查看进程上下文切换的情况,如下表示自发(如I/O等待)的上下文切换为1,非自发(如时间片超时会被更高优先级进程抢占)的上下文切换为10。

voluntary_ctxt_switches: 1 nonvoluntary_ctxt_switches: 10

实时调度发生的情况可能是软件(如定时器超时)或硬件引发的

容器也会使用CFS在各个cgroup中进行调度,更多细节参见understanding-linux-container-scheduling

可以将1个CPU分为1000份,即1 CPU = 1000m。但在CFS中,会将1 CPU分为1024份,称为1024 CPU shares,即分配500m的CPU等同于分配了512 CPU shares。 CFS的调度周期由cpu.cfs_period_us定义,默认100m。意味着,如果cpu.cfs_period_us为100m,则1CPU就是100ms,而2500m CPU就是250ms,CFS会将一个周期切分为多个时间片,最小时间片由sched_cfs_bandwidth_slice_us定义,默认5ms。

参考 Linux CFS调度器

本文来自博客园,作者:charlieroro,转载请注明原文链接:https://www.cnblogs.com/charlieroro/p/12133100.html



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3