操作系统是计算机系统的核心基石,对于系统架构师而言,深入理解其核心概念是至关重要的。在各类技术考试与面试中,这部分知识也常作为考察重点。
进程与线程的核心区别
- 进程:是计算机进行资源分配的基本单位。它拥有独立的地址空间、文件描述符表、信号处理表等资源。
- 线程:是 CPU 调度和执行的基本单位。线程属于某个进程,并共享该进程的资源(如内存、文件句柄),但拥有自己独立的栈、寄存器和线程局部存储。
重要考点辨析:当问题指向“CPU调度单位”时,答案是线程;当问题指向“资源分配单位”时,答案是进程。这一点已在近年考试中出现。
性能差异:由于线程共享地址空间,线程切换时不需要刷新TLB;而进程切换涉及地址空间的改变,必须刷新TLB。这使得进程切换的开销通常比线程切换大一个数量级。
TLB小知识:TLB(Translation Lookaside Buffer,快表)是MMU(内存管理单元)的一部分,本质上就是页表的高速缓存。它存储了近期最可能被访问的虚拟地址到物理地址的映射,避免了每次地址翻译都需要查询内存中多级页表的昂贵开销,从而极大提升了访问速度。
进程的五态模型
经典的进程三态模型(就绪、运行、阻塞)描述了进程在内存中的基本活动。而五态模型在此基础上进行了扩展,增加了“新建”和“终止”状态,更完整地刻画了进程从生到死的完整生命周期。

-
新建 (New)
- 含义:进程正在被创建。操作系统已为其分配进程标识符(PID),正在建立进程控制块(PCB),但指令和数据尚未完全载入内存。
- 转换:完成创建和必要的资源分配后,进程进入就绪态。
-
就绪 (Ready)
- 含义:进程已获得除CPU之外的所有必需资源,万事俱备,只等待CPU时间片。系统中的就绪进程排成就绪队列。
- 转换:当操作系统的调度器选中它时,它获得CPU,进入运行态。
-
运行 (Running)
- 含义:进程的指令正在CPU上执行。在单核CPU系统中,任一时刻只有一个进程处于运行态。
- 转换:
- 运行 -> 就绪:通常是因为分配给它的时间片用完,或被更高优先级的就绪进程抢占。
- 运行 -> 阻塞:进程因需要等待某个事件(如I/O操作完成、等待信号)而主动放弃CPU。
- 运行 -> 终止:进程正常执行结束,或因出错被操作系统强制终止。
-
阻塞 / 等待 (Blocked / Waiting)
- 含义:进程正在等待某个外部事件的发生(如磁盘I/O、网络数据)。在此状态下,即使分配CPU给它也无法执行,因此不参与CPU调度。
- 转换:当等待的事件发生(如I/O完成),进程被唤醒,重新放回就绪队列。
-
终止 (Exit / Terminated)
- 含义:进程已结束执行。操作系统开始回收其占用的内存、文件等资源,但PCB中的退出状态等信息可能暂存以供查询。
- 转换:生命周期终点,无后续转换。
模型对比与核心要点:
- 三态模型聚焦于进程在内存中的活动(就绪、运行、阻塞)。
- 五态模型通过增加“新建”和“终止”态,强调了进程创建与销毁的系统开销和过程。
- 状态转换的发起者:
- 进程自身可引起:运行->阻塞(如发起系统调用)、运行->终止。
- 操作系统(内核)可引起:新建->就绪、就绪<->运行(调度)、阻塞->就绪(事件完成唤醒)、运行->终止(强制终止)。
- 状态属于进程:同一个程序可以对应多个进程,每个进程独立经历状态变迁。
线程同步的三大核心机制
在多线程编程中,为了确保对共享资源的安全访问和线程间的协调合作,必须使用同步机制。互斥锁、信号量和条件变量是三大基础同步原语。
快速记忆与考点:
- 问“避免忙等待” -> 选择条件变量。
- 问“限制最多N个线程同时访问” -> 选择信号量。
下图清晰地对比了三者的核心作用与差异:

1. 互斥锁 (Mutex)
- 核心思想:独占访问,一把钥匙开一把锁。
- 是什么:用于实现最简单的互斥访问。好比一个只有一个座位的房间,谁拿到钥匙谁进入,出来时交出钥匙。
- 核心操作:
lock() / acquire(): 尝试获取锁。若锁已被占用,则调用线程阻塞。
unlock() / release(): 释放锁,唤醒一个等待此锁的线程。
- 主要用途:保护临界区,确保同一时刻只有一个线程访问共享数据,解决数据竞争问题。
- 关键特性:
- 所有权概念:通常要求“谁加锁,谁解锁”。
- 二进制状态:只有“锁定”和“未锁定”两种状态。
2. 信号量 (Semaphore)
- 核心思想:资源计数器,允许多个但有限制的并发访问。
- 是什么:一个非负整数计数器,用于控制对一类资源的并发访问数量。好比一个拥有多把相同钥匙的钥匙串,或显示剩余车位数的指示牌。
- 核心操作:
wait() / P() / acquire(): 信号量值减1。如果值变为负,则线程阻塞。
signal() / V() / release(): 信号量值加1。如果有线程因此阻塞,则唤醒其中一个。
- 主要用途:
- 限制并发线程数(如数据库连接池上限为10)。
- 实现生产者-消费者模型(控制缓冲区空/满)。
- 关键特性:
- 无所有者:任何线程都可以执行
signal 操作。
- 计数能力:可初始化为N,表示资源的初始数量。
- 二进制信号量:当计数初始化为1时,可模拟互斥锁,但无所有权。
3. 条件变量 (Condition Variable)
- 核心思想:主动等待与通知,用于线程间的条件协作。
- 是什么:一种允许线程在某个条件不满足时主动休眠,并在条件可能满足时被其他线程唤醒的机制。必须与一个互斥锁结合使用。
- 核心操作:
wait(lock, [predicate]): 原子地释放锁并使线程进入等待状态。被唤醒后,会重新获取锁,并可选择检查条件谓词。
notify_one(): 唤醒一个等待线程。
notify_all(): 唤醒所有等待线程。
- 主要用途:
- 实现复杂的等待/通知逻辑(如“缓冲区非空时才消费”)。
- 避免“忙等待”,让等待条件的线程释放CPU,提高效率。
- 关键特性:
- 协同工作:条件变量本身不保护数据,数据安全由关联的互斥锁保证。
- 虚假唤醒:等待的线程可能在没有
notify 的情况下被唤醒。因此,wait 调用通常应放在 while 循环中,以重新检查条件是否真正满足。
通俗比喻:
- 互斥锁是“一夫当关”,保证独占。
- 信号量是“限量入场券”,控制流量。
- 条件变量是“叫号等待”,等通知再办事。
在实际开发中,应优先使用互斥锁解决基本的数据竞争问题;当需要精细控制并发度或实现复杂的线程间协作顺序时,再考虑使用信号量或条件变量。
本文梳理了操作系统关于进程、线程及同步机制的核心知识点,希望能为你的学习和备考提供清晰的脉络。想深入探讨更多计算机系统原理,可以访问 云栈社区 的「计算机基础」板块,那里有更多系统的教程和开发者们的实战分享。
|