写多线程程序的人,对"线程唤醒"这件事不会陌生。一个线程在等条件变量,另一个线程pthread_cond_signal通知它,它就醒了,然后继续执行。整个过程在应用层看起来干净利落——signal 一下,对面就跑起来了。但如果有人问你:当你调用pthread_cond_signal之后,被唤醒的那个线程,到底要经历多少步才能真正拿到 CPU 开始执行?你可能会说:内核把它从等待队列移到就绪队列,调度器选中它,然后它就跑了。这个回答大方向没错,但把中间最有意思的部分全跳过了。那个"选中"二字背后,是 CFS 调度器里一整套多层决策机制——从唤醒时的 CPU 选择、vruntime 的重新定位、抢占判断、到最终的pick_next_task_fair逐级筛选。每一层都有自己的判断逻辑,哪一层的结果都可能决定你的线程是立刻拿到 CPU,还是在就绪队列里再多等几毫秒。这篇文章要做的事情很具体:从一个线程被唤醒的那一刻开始,沿着 Linux 内核的实际执行路径,一步一步追踪它经过的每一层判决,直到它最终被pick_next_task_fair选中、完成上下文切换、真正开始执行。不泛泛讲"CFS 调度器的原理",而是具体到每一层的函数调用、判断条件和源码逻辑,搞清楚一个线程从就绪到拿到 CPU 的完整旅程。主要参考 Linux v6.5 的kernel/sched/core.c和kernel/sched/fair.c。选 v6.5 而不是 6.6+