在 Linux POSIX 线程编程中,调度策略直接决定了线程如何竞争 CPU 资源,也是面试与嵌入式、实时开发中的高频考点。本文从原理、特点、适用场景到代码示例,彻底讲清楚三种调度策略:SCHED_OTHER、SCHED_FIFO、SCHED_RR。
一、基础概念
Linux 把调度策略分为两大类:
- 普通调度策略:
SCHED_OTHER(系统默认) - 实时调度策略:
SCHED_FIFO、SCHED_RR
优先级规则:
- 实时策略优先级:1 ~ 99,数值越大优先级越高
- 普通策略优先级:固定为 0
- 任何实时线程 > 普通线程,只要有实时线程可运行,普通线程会被完全抢占
二、SCHED_OTHER(默认分时调度)
特点
- 非实时、公平分时调度
- 优先级固定为 0,不能修改
- 依赖
nice值调整权重,值越小越优先 - 由 CFS 公平调度器管理,不会饿死线程
- 适合绝大多数普通应用
适用场景
业务逻辑、后台服务、GUI 程序、普通计算任务等对响应时间不敏感的场景。
三、SCHED_FIFO(实时先进先出)
特点
- 实时调度,无时间片
- 一旦占用 CPU,除非阻塞、被更高优先级抢占或主动退出,否则绝不释放
- 同优先级线程:先来先服务,不主动切换
- 高优先级线程可完全抢占低优先级线程
注意
- 多核环境下,不同核心可同时运行不同优先级线程
- 必须绑定到同一核心,才能观察到严格的独占效果
适用场景
工控、实时采集、硬实时任务,要求极低延迟。
四、SCHED_RR(实时时间片轮转)
特点
- 实时调度,带时间片(默认约 100ms)
- 高优先级依旧抢占低优先级
- 同优先级线程轮流执行,时间片用完自动切换
- 不会像 FIFO 那样被单个线程独占 CPU
适用场景
音视频、实时数据处理、多路实时任务,既要求实时性又希望公平。
五、三种策略核心对比
表格
| 策略 | 类型 | 优先级 | 时间片 | 同优先级调度 | 抢占特性 |
|---|---|---|---|---|---|
| SCHED_OTHER | 普通 | 0 | 有 | 公平轮转 | 低 |
| SCHED_FIFO | 实时 | 1-99 | 无 | 不切换,独占 | 强抢占 |
| SCHED_RR | 实时 | 1-99 | 有 | 时间片轮转 | 强抢占 |
六、关键知识点总结
- sleep、printf、锁、IO 都会阻塞线程并释放 CPU,会让低优先级线程获得运行机会。
- 多核 CPU上不同核心可同时运行不同优先级线程,想观察抢占必须绑核。
- SCHED_FIFO 同优先级:谁先运行谁独占,另一个线程完全不运行。
- SCHED_RR 同优先级:轮流运行,自动切换,公平不卡死。
- 实时线程必须使用
root权限运行。
七、简单示例:SCHED_RR 同优先级轮转
c
运行
#define _GNU_SOURCE #include <stdio.h> #include <pthread.h> #include <unistd.h> #include <sched.h> void *funcA(void *arg) { while (1) { printf("A "); } } void *funcB(void *arg) { while (1) { printf("B "); } } int main() { pthread_t tidA, tidB; pthread_attr_t attrA, attrB; struct sched_param param; pthread_attr_init(&attrA); pthread_attr_init(&attrB); // 调度策略 RR pthread_attr_setschedpolicy(&attrA, SCHED_RR); pthread_attr_setschedpolicy(&attrB, SCHED_RR); // 同优先级 90 param.sched_priority = 90; pthread_attr_setschedparam(&attrA, ¶m); pthread_attr_setschedparam(&attrB, ¶m); pthread_attr_setinheritsched(&attrA, PTHREAD_EXPLICIT_SCHED); pthread_attr_setinheritsched(&attrB, PTHREAD_EXPLICIT_SCHED); pthread_create(&tidA, &attrA, funcA, NULL); pthread_create(&tidB, &attrB, funcB, NULL); pthread_join(tidA, NULL); pthread_join(tidB, NULL); return 0; }编译运行:
bash
运行
gcc sched_rr.c -o rr -pthread sudo ./rr运行效果:A、B 按时间片交替批量打印。