Appearance
题目
某博物馆最多可以容纳 500 人同时参观,有一个出入口,该出入口一次仅允许一个人通过。参观者的活动描述如下:
cobegin
参观者进程 i:
{
...
进门;
...
参观;
...
出门;
...
}
coend请添加必要的信号量和 P、V(或 wait()、signal())操作,以实现上述过程中的互斥与同步。要求写出完整的过程,说明信号量的含义并赋初值。
解析
关系拆解
| 约束 | 类型 | 用什么信号量 |
|---|---|---|
| 博物馆里最多 500 人 | 同步(容量限制) | empty(init = 500) |
| 出入口一次只能 1 人通过 | 互斥(共享出入口) | mutex(init = 1) |
注意"出入口"既被进门用、也被出门用——所以进门和出门都要 P(mutex) 包夹。但参观本身不占用出入口,不需要锁。
信号量与代码
c
semaphore empty = 500; // 博物馆剩余可容纳人数
semaphore mutex = 1; // 出入口互斥(一次只能 1 人通过)
visitor() {
P(empty); // 等到博物馆有名额
P(mutex); // 占用出入口
进门;
V(mutex); // 让出出入口
参观; // 在馆内参观,无需锁
P(mutex); // 出门也要占用出入口
出门;
V(mutex); // 让出出入口
V(empty); // 释放一个名额(人走了)
}信号量含义说明(答题必写)
| 信号量 | 初值 | 含义 |
|---|---|---|
empty | 500 | 博物馆剩余名额数;进入前 P,离开后 V |
mutex | 1 | 出入口互斥锁;进门、出门动作各自包在 P-V 之间 |
易错点
编者注(易错点):
P(empty)必须在P(mutex)之前——典型的"同步信号量先于互斥信号量获取"。如果调换顺序,第 501 个游客会拿到 mutex 但卡在 P(empty) 上 → 出入口被锁死、谁也进不去也出不来 → 全部死锁。出门时不能 V(empty) 在 V(mutex) 之前——但这一条比较弱。两种顺序都不会死锁;放 V(mutex) 前只是让"通知名额释放"早 1 个原子操作发生,没有功能差别。考试两种写法都给分,但建议按"先放手中的资源(mutex),再发广播(empty)"这种习惯写法。
参观环节不能放在 mutex 内——题目明确说"出入口一次一人",没说"博物馆里同一时刻只能 1 人在参观"。如果把"参观"也包进 mutex,会变成"博物馆每次只允许 1 人"——与"最多 500 人"矛盾,且违背题意。
不能用一个信号量同时管 500 人和出入口——这是初学者常犯的错。500 人是容量约束(用计数信号量 init=500),出入口是互斥约束(用二值信号量 init=1),两者根本不是一个量级,必须分开两个信号量。
本题不需要"front / rear"等队列指针——这是单纯的"容量 + 互斥"题,不涉及队列实现。如果题目要求"按到达顺序进入"再考虑公平队列,本题不要求。