linux的进程调度发生在什么情况下
Linux 进程调度(Process Scheduling)会在多种情况下触发,主要由内核的调度器(如CFS、O(1)调度器等)根据策略和事件决定。以下是触发调度的典型场景:
1. 主动调度(Voluntary)
- 系统调用显式让出CPU
进程通过系统调用(如 sched_yield()
、nanosleep()
)主动放弃CPU。
- 阻塞操作
当进程因I/O、锁、信号量等资源不可用而阻塞时,内核会将其移出运行队列,触发调度。
2. 被动调度(Involuntary)
- 时间片耗尽(Time Slice Expired)
Linux 的 CFS 调度器通过虚拟时间(vruntime)公平分配CPU。当进程耗尽其时间片(由 sched_latency_ns
和 sched_min_granularity_ns
控制),会被重新排队,调度新进程。
- 更高优先级进程就绪
实时进程(RT Priority)或更高优先级的普通进程(Nice值更低)进入可运行状态时,可能抢占当前进程。
3. 中断和异常
- 硬件中断
例如网卡收到数据包、磁盘I/O完成时,中断处理程序执行后可能唤醒等待该事件的进程,触发调度。
- 时钟中断(Tick)
内核周期性时钟中断(如 CONFIG_HZ=1000
时每秒1000次)检查是否需要调度(通过 scheduler_tick()
更新进程状态和时间片)。
4. 进程状态变化
- 进程创建/终止
fork()
、exit()
等操作会修改任务队列,触发调度。
- 进程唤醒(Wake Up)
等待中的进程被唤醒(如 wake_up()
),若其优先级高于当前进程,可能触发抢占。
5. 显式抢占(Explicit Preemption)
- 内核抢占(Kernel Preemption)
配置 CONFIG_PREEMPT
时,内核代码(除关键区域)可被高优先级进程抢占。
- 用户态抢占(User Preemption)
从内核态(系统调用、中断)返回用户态前,检查是否需要调度。
6. 其他特殊情况
- CPU负载均衡
多核系统中,调度器可能将进程迁移到空闲CPU,触发调度。
- cgroup 限制
进程超出其所属Cgroup的CPU配额时会被限制。
调度触发的底层机制
- 调用
schedule()
函数
上述所有场景最终通过调用内核的 schedule()
函数完成实际切换。
- 抢占标记(TIF_NEED_RESCHED)
内核通过设置当前线程的 need_resched
标志,在安全点时触发调度。
观察调度行为
- 工具
使用 perf sched
、ftrace
或 /proc/<pid>/schedstat
跟踪调度事件。
- 日志
内核启动参数添加 sched_debug
可查看详细调度信息。
通过理解这些触发条件,可以更好地优化进程优先级(Nice/RT)、减少阻塞、或调整调度策略(如 chrt
修改实时策略)。