AIGC标识 操作系统并发与同步:临界区、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 就想读者-写者;
看到共享数据结构和操作过程就想管程;
看到缓冲区队列就想消息机制。
posted @ 2026-07-27 11:07  ziziranran  阅读(6)  评论(0)    收藏  举报
下面这份是完整代码,已经把《失语者 - 蔡健雅》放在第一首,并把 `loop` 改成 `none`,这样播完第一首会继续切到后面的歌。 ```html
```