真实面经题目 · 原创解析

线程调度和进程调度的区别?

进程是资源分配和地址空间隔离的基本单位,线程是 CPU 执行流和调度的基本单位。在现代 Linux 中,内核调度器实际调度的是 task_struct 表示的可调度实体,因此二者的关键差异不在于两套完全不同的调度器,而在于切换时涉及的资源上下文、地址空间、共享关系和开销不同。

出现于:阿里巴巴 · 算法

60 秒回答模板

传统教材会说进程调度是在多个进程之间分配 CPU,线程调度是在多个线程之间分配 CPU。更准确地说,现代操作系统尤其是 Linux,调度器调度的是内核可见的执行实体,也就是 task_struct。一个单线程进程有一个 task_struct,多线程进程中的每个线程通常也各有一个 task_struct。区别在于,进程通常拥有独立地址空间、文件表等资源,进程间切换可能要切换 mm_struct、页表和 TLB 上下文;同一进程内线程共享地址空间和大量进程资源,线程间切换通常不需要切换地址空间,所以一般更轻量。但这不是绝对的,线程切换仍然要保存和恢复寄存器、栈、调度状态,也会带来缓存扰动和同步开销。调度策略上,Linux 的 CFS、实时调度、deadline 等策略作用在可调度任务上,线程和进程本质上都按调度实体参与竞争。面试中要避免简单说“进程调度开销大、线程调度开销小”就结束,最好补充 Linux 下 task_struct、地址空间共享、用户级线程是否被内核感知这几个点。

考点 概念定位
主线 调度对象
易错点 只回答“进程是资源分配单位,线程是调度单位”,没有解释…

深入解析

01

概念定位

进程更偏向资源容器,通常拥有独立的虚拟地址空间、打开文件、信号处理、权限凭据等资源;线程更偏向执行流,表示一条可以被 CPU 执行的控制路径。一个进程至少有一个线程,多线程进程中的线程共享同一个进程的大部分资源,但各自拥有寄存器上下文、内核栈、用户栈、线程局部存储和调度状态。

02

调度对象

严格说,现代 Linux 内核并不是先有一个完全独立的进程调度器,再有一个完全独立的线程调度器。Linux 调度器面对的是 task_struct,每个内核可见的执行流都可以作为调度对象。单线程进程的 task_struct 可以理解为这个进程的主执行流;多线程程序中,每个线程也有自己的 task_struct。

03

资源上下文

进程之间通常不共享地址空间,进程调度切换时可能需要切换页表、mm_struct、虚拟内存映射以及相关的 TLB 上下文。线程如果属于同一个进程,通常共享同一个地址空间和大量进程级资源,线程之间切换时一般不需要切换页表,资源上下文变化更少。

04

切换成本

上下文切换至少包括保存当前执行流的 CPU 寄存器、程序计数器、栈指针、调度状态,并恢复下一个执行流的上下文。进程切换可能额外带来地址空间切换、TLB 失效、缓存局部性下降等成本;线程切换如果共享地址空间,通常避免了其中一部分成本。

05

Linux 实现

Linux 中 task_struct 是核心的任务描述结构,包含调度信息、状态、优先级、CPU 亲和性、上下文、信号、内存描述符等引用。线程之间共享哪些资源,主要由 clone 创建时传入的共享标志决定,例如共享地址空间、文件描述符表、文件系统信息、信号处理等。

06

调度策略

Linux 的普通调度、实时调度和 deadline 调度关注的是可运行任务的优先级、虚拟运行时间、实时优先级、deadline 参数、CPU 亲和性等。一个多线程程序的多个线程可以分别进入就绪队列,分别竞争 CPU;不同线程也可以设置不同优先级或亲和性。

07

用户线程

如果是纯用户级线程,内核看不到每个用户线程,只看到承载它们的内核线程或进程,那么内核不会直接调度这些用户线程,用户态运行时负责在它们之间切换。如果是 1:1 线程模型,每个用户线程对应一个内核线程,内核就可以分别调度它们。

易错点

  • 只回答“进程是资源分配单位,线程是调度单位”,没有解释现代 Linux 中 task_struct 统一调度模型。
  • 把进程调度和线程调度说成两套完全独立的内核机制,忽略 Linux 调度器实际调度可运行 task。
  • 绝对化地说线程切换一定比进程切换快,没有说明同进程线程共享地址空间这个前提。
  • 混淆用户级线程和内核级线程,默认所有线程都能被内核直接调度。
  • 认为同一进程内所有线程共享一切资源,忽略每个线程仍有独立栈、寄存器上下文、调度状态和线程局部数据。

面试官追问

Linux 中进程和线程到底有什么关系?

Linux 内核使用 task_struct 描述可调度任务。传统意义上的进程可以看作拥有相对独立资源的一组 task,线程则是与同组其他 task 共享更多资源的 task。

为什么说线程切换通常比进程切换快?

因为同一进程内线程共享地址空间,切换时通常不需要切换页表和完整内存上下文,也更容易保留部分地址转换和缓存局部性。进程切换更可能涉及 mm_struct、页表、TLB 和缓存状态变化。

线程调度一定比进程调度更高效吗?

不一定。理论上同进程线程切换少了地址空间切换成本,但如果线程数量过多、频繁阻塞唤醒、严重锁竞争、跨 CPU 迁移或破坏缓存局部性,整体效率可能反而下降。

用户级线程和内核级线程对调度有什么影响?

用户级线程由用户态运行时管理,内核通常只能调度承载它们的内核线程,因此不会直接感知每个用户线程。内核级线程被内核直接感知,可以独立进入就绪队列、阻塞、唤醒和分配 CPU。

多线程程序能不能真正并行?

如果多个线程是内核可见线程,并且系统有多个 CPU 核心,调度器可以把它们分配到不同核心上同时运行,从而实现真正并行。如果是单核,只能通过时间片切换形成并发。