操作系统并发与同步:临界区、PV、管程与进程通信速记
本文由一次操作系统原理刷题对话整理而来,主要用于复习并发、同步、互斥和进程通信相关考点。
这一组题集中在操作系统的并发、同步、互斥和进程通信。不要一上来死背名词,可以先抓三个问题:
- 谁在抢同一个资源?
- 谁必须等谁完成?
- 数据到底通过什么方式传递?
1. 临界区四段怎么分
一段访问共享资源的程序,教材里常拆成四个部分:
- 进入区:申请进入临界区,例如
P(lock)或while TS(&lock)。它是在拿锁,还没有真正操作共享资源。 - 临界区:真正访问共享资源的代码,例如查余票、判断余票、扣减余票,或者读取余额、修改余额、写回余额。
- 退出区:释放锁,例如
V(lock)或lock = FALSE。它表示当前进程已经用完共享资源。 - 剩余区:和共享资源无关的普通代码,例如打印行程单、输出提示、执行其他工作。
临界资源是一次只能一个进程访问的资源,临界区是访问这类资源的那段程序。这里的 critical 更接近“关键的”,不是说资源本身危险。
一个简单记法:
P/TS 是进门前拿锁
真正碰共享数据的代码才是临界区
V 是出来后释放锁
2. P/V 和 Test-and-Set 的区别
P 操作表示申请资源、等待、加锁;V 操作表示释放资源、通知、解锁。
可以粗略理解为:
P(S): S--,如果 S < 0,则阻塞当前进程
V(S): S++,如果有进程等待,则唤醒一个等待进程
所以:
P(1):通常能通过,S 变成 0
P(0):通常会阻塞,S 变成 -1
Test-and-Set 是硬件原子指令。常见约定是:
W = 0:锁空闲,可以进
W = 1:锁已被占用,继续等
while TS(W) 是自旋等待,进不去时会不断测试,会占用 CPU;而信号量的 P 操作通常会让进程阻塞等待,不一直空转。
容易混的地方是:
信号量 mutex = 1:资源可用
Test-and-Set 锁变量 W = 1:锁被占用
这两个数字含义不一样,题目里要看清楚是哪一种机制。
3. 信号量初值怎么看
判断信号量初值时,先看它表示“资源数量”还是“互斥锁”。
- 表示资源数量:初值就是一开始有几个资源。
- 表示互斥锁:初值通常是
1,表示一开始没人占用,可以进入。
生产者-消费者问题中:
empty = N // 一开始有 N 个空缓冲区
full = 0 // 一开始没有产品
mutex = 1 // 一开始缓冲区没人占用
读者-写者问题中:
rc = 0 // 一开始没有读者
mutex = 1 // 保护 rc 的锁,一开始可用
w = 1 // 共享文件一开始没人占用
这里的 mutex 不是 N。它不是表示“允许 N 个读者读”,而是只保护 rc++ 和 rc--,所以一次只能一个进程改计数器,初值必须是 1。
4. P/V 顺序:先同步,后互斥
同时有同步信号量和互斥信号量时,常见顺序是:
进入时:先 P(同步信号量),再 P(互斥信号量)
退出时:先 V(互斥信号量),再 V(同步信号量)
例如消费者:
P(full); // 先确认有产品
P(mutex); // 再互斥进入缓冲区
取产品;
V(mutex); // 先释放缓冲区
V(empty); // 再通知有空位
如果反过来先 P(mutex) 再 P(full),缓冲区为空时,消费者会先占住缓冲区锁,然后卡在 P(full)。生产者想放产品又拿不到 mutex,就可能死锁。
5. 生产者-消费者模型
标准写法如下:
// 生产者
P(empty);
P(mutex);
放产品;
V(mutex);
V(full);
// 消费者
P(full);
P(mutex);
取产品;
V(mutex);
V(empty);
它里面有两类关系:
- 生产者和消费者之间:既互斥又同步。互斥是因为都要访问缓冲区;同步是因为空了不能取,满了不能放。
- 生产者和生产者之间:主要是互斥,因为多个生产者不能同时乱改同一个缓冲区结构。
- 消费者和消费者之间:主要是互斥,因为多个消费者不能同时取同一个位置。
同类之间一般不是同步,因为它们不是“你完成后我才能继续”的合作关系,而是在竞争同一个缓冲区。
6. 读者-写者模型
读者-写者问题的规则是:
读读可以同时
读写不能同时
写写不能同时
常见变量含义:
rc:当前正在读的读者数量
mutex:保护 rc 的互斥信号量
w:保护真正的共享文件
读者进入时:
P(mutex);
rc = rc + 1;
if (rc == 1) P(w);
V(mutex);
读操作;
读者退出时:
P(mutex);
rc = rc - 1;
if (rc == 0) V(w);
V(mutex);
写者:
P(w);
写操作;
V(w);
核心思想是:第一个读者 P(w),挡住写者;最后一个读者 V(w),放行写者。
这里可以把 mutex 理解成“小锁”,只锁读者计数器;把 w 理解成“大锁”,锁共享文件。多个读者读文件时不占用 mutex,所以读者之间可以并发读。
7. 管程是什么
管程是更高级的同步机制,可以理解成:
共享数据结构 + 操作这些数据的一组过程 + 条件变量 + 自动互斥
管程的特点:
- 同一时刻管程内最多只有一个进程活动。
- 它可以解决互斥,也可以用条件变量解决同步。
- 它不是让程序员到处写一组 P/V,而是把共享数据和访问规则封装起来。
所以题目里看到“共享数据结构”和“一组操作过程”,基本就是管程的核心。
8. 同步和互斥的区别
互斥:抢同一个资源,不能同时用。
同步:进程之间有先后配合关系,一方要等另一方产生条件。
例子:
互斥:多人同时改订票数据库、账户余额、库存
同步:生产者生产后消费者才能消费
有些场景看起来也像“等待”,但不一定是同步。比如两个人轮流用一台游戏机,后一个人等前一个人下机,本质上是等资源释放,更偏互斥;生产者和消费者那种“没有产品就不能消费”,才是典型同步。
9. 进程通信方式怎么区分
几种常考通信方式:
- 共享内存:多个进程访问同一块内存,拷贝少、速度快,适合大量数据交换,但需要自己处理同步互斥。
- 管道通信:通过一个打开的共享文件或管道传字节流,读空会等,写满会等,常体现同步通信。
- 消息机制:公共缓冲区组织成队列,发送进程把消息放入队列,接收进程再取。关键词是消息、缓冲区、队列。
- 信箱通信:发送者把信件放进信箱,接收者之后再取,优点是异步。
receive通常需要信箱名和接收缓冲区地址。 - 信号量:主要用于同步和互斥,传递的是信号或状态,不适合传业务数据,因此传递数据量最少。
- 套接字:socket,常用于本机或网络进程通信,关键词是地址、端口、网络连接。
直接通信方式里的发送原语一般是:
send(receiver, message)
发送时指定“发给谁”,不用写 sender,因为当前执行 send 的进程本身就是发送者。
10. 常见易混点
- 共享内存是“拷贝少”,不是“传递数据量最少”。传递数据量最少的是信号量。
- 公共缓冲区组成队列,通常指消息机制。
- 打开的共享文件连接两个进程,通常指管道通信。
- 直接通信的
send写接收者,不写发送者。 - 相关进程指共享资源、交换信息或互相影响的进程;无关进程是各干各的,互不影响。
- 查询共享数据、判断、修改写回这三步必须作为整体互斥执行,否则容易出现超卖、余额错误、库存错误。
最后用一句话收束:
看到共享数据读写就想临界区;
看到 P/V 就想申请和释放;
看到 empty/full 就想生产者-消费者;
看到 rc/w/mutex 就想读者-写者;
看到共享数据结构和操作过程就想管程;
看到缓冲区队列就想消息机制。

浙公网安备 33010602011771号