使用 ps -eo pid,tid,cls,pri,rtprio,nice,comm 查看调度策略:cls=ts 为 cfs(nice 有效),cls=ff/rr 为实时(rtprio 有效,nice 无效);实时进程受 sched_rt_runtime_us/period_us 和 cgroup 配额限制;避免实时线程调用睡眠函数。

如何查看当前进程的调度策略和优先级
Linux 进程的调度策略不是默认隐藏的,但得用对工具才能一眼看清。ps 默认不显示调度相关字段,chrt 又只对单个进程有效,容易漏掉上下文。
推荐组合使用:ps -eo pid,tid,cls,pri,rtprio,nice,comm —— 其中 cls 是调度类(如 TS 表示 CFS,FF 表示 SCHED_FIFO),rtprio 是实时优先级(仅对实时策略有效),nice 对 CFS 有效。
-
cls=FF或cls=RR表示该线程启用了实时调度,此时nice值无意义,真正起作用的是rtprio - 普通用户进程通常为
cls=TS,rtprio=-(即空),nice在 -20 到 19 之间 - 注意
tid(线程 ID)列:一个进程多个线程可能有不同调度策略,尤其在绑核或显式调用sched_setscheduler后
为什么 sched_setscheduler 调用失败返回 EPERM
不是权限没加够,而是内核限制比想象中更细。即使你是 root,也受 /proc/sys/kernel/sched_rt_runtime_us 和 /proc/sys/kernel/sched_rt_period_us 约束。
典型错误现象:sched_setscheduler(pid, SCHED_FIFO, ¶m) 返回 -1,errno == EPERM,但 geteuid() == 0。
- 检查是否已超出实时带宽配额:
cat /proc/sys/kernel/sched_rt_runtime_us默认是 950000(即 95%),设为 -1 才表示不限制 - 确认目标进程未被 cgroup v1 的
cpu.rt_runtime_us限制(cgroup v2 使用cpu.max) - 内核编译时若关闭
CONFIG_RT_GROUP_SCHED,则全局配额生效;开启后,配额按 cgroup 分配,root cgroup 的限制仍会兜底
实时任务卡死系统?别急着换 SCHED_OTHER
SCHED_FIFO/SCHED_RR 不等于“一定霸占 CPU”,问题常出在逻辑阻塞点没处理好,而非策略本身。
真实场景中,一个 SCHED_FIFO 线程在 read() 等待管道数据、或持有自旋锁时间过长,都会导致其他实时线程饿死,甚至触发 watchdog 报错 watchdog: BUG: soft lockup。
- 避免在实时线程中调用可能睡眠的系统调用:
malloc、printf、open、sem_wait(除非是sem_trywait) - 必须等待事件时,用
poll+timeout=0轮询,或改用eventfd+epoll(需确保 epoll_wait 不被信号中断挂起) - 绑定 CPU 核心(
sched_setaffinity)能减少干扰,但无法解决自身逻辑阻塞 —— 这点常被忽略
CFS 调度下 nice 值的实际影响很弱
别再迷信 “把 nice 设成 -20 就能抢到更多 CPU”—— 在负载不高或非计算密集型场景下,nice 几乎看不出差别。
CFS 的虚拟运行时间(vruntime)计算公式里,nice 只影响权重(load.weight),而权重差异在低负载时被归一化压缩得很小。实测中,两个 nice=-20 和 nice=0 的 busy-loop 进程,在 4 核机器上跑满时,CPU 时间分配偏差通常
- 真正起效的场景:多任务长期竞争、且至少有一个 CPU 核处于 100% 负载
-
nice对 I/O 密集型进程几乎无影响,因为它们大部分时间在TASK_INTERRUPTIBLE状态,不参与 vruntime 竞争 - 想精细控权,不如用 cgroup v2 的
cpu.weight(范围 1–10000),它绕过 nice 的离散分级,直接映射为调度权重
调度策略不是开关,是和 workload、硬件拓扑、cgroup 配置、甚至内核启动参数(比如 isolcpus)咬合在一起的。动其中一环前,先看清楚它咬住了哪几颗牙。









