操作系统期末考试题

一、选择题 (每题1分,共20分)

1. 设计批处理多道系统时,首先要考虑的是( )

  • 答案: B. 系统效率和吞吐量
  • 解释: 批处理系统的设计重点在于如何提高系统的效率和吞吐量,因为批处理系统通常处理大量作业并以批次方式执行,目标是高效地完成作业处理并提高系统的整体吞吐能力。

2. 若当前进程因时间片用完而让出处理机时,该进程应转变为( )状态。

  • 答案: A. 就绪
  • 解释: 在时间片轮转调度算法中,进程用完时间片后,进程并不会立即终止或挂起,而是被转到就绪队列等待下一次调度,因此转变为就绪状态。

3. 计算机分时系统与实时系统的主要区别是( )

  • 答案: B. 响应时间
  • 解释: 分时系统主要是为了提高系统的交互性和资源共享效率,响应时间较长;而实时系统对响应时间要求非常严格,必须在规定时间内完成任务。

4. 银行家算法破坏了下述哪一个死锁必要条件( )

  • 答案: A.保持申请条件(更准确说法是“请求和保持”条件)
  • 解释: 银行家算法的基本思想是:在进程提出资源申请时,先判断如果分配给该进程资源后系统是否还处于安全状态,如果安全则分配,否则不分配。这样就破坏了“请求和保持”条件,因为进程在申请资源时,如果没有足够的资源,它不会一直保持已占有的资源去等待新申请的资源,而是释放已占有的资源(处于等待状态),避免了进程在占有部分资源的同时又申请新资源可能导致死锁的情况。不剥夺条件是指进程已获得的资源在未使用完之前不能被剥夺,银行家算法并没有直接破坏该条件;部分分配条件是指进程在申请资源时,只要获得了一部分就先运行,银行家算法也没有针对此条件进行破坏;环路等待条件是指存在一组进程,它们相互等待对方占有的资源形成环路,银行家算法也不是直接针对该条件进行破坏。

5. 作业调度程序是从处于( )状态的作业中选取一个作业并把它装入主存。

  • 答案: B. 后备
  • 解释: 作业调度程序负责从后备队列(即在外存中等待的作业队列)中选择一个作业,将其调入主存,准备执行。

6.支持程序浮动的地址转换机制是( )

A. 页式地址转换 B. 段式地址转换 C. 静态重定位 ✅ D. 动态重定位

  • 解释 Explanation:
    • 动态重定位(Dynamic relocation) 是一种允许程序在内存中浮动(floating,即可以在任何位置加载和运行)的机制。它通常通过一个重定位寄存器(如基址寄存器)实现地址转换,支持程序运行时的地址动态变换。
    • 静态重定位是编译或装载时完成的,不能在运行时改变。
    • 页式/段式是地址空间管理方式,不能单独保证运行时地址浮动。

7.下面属于动态优先数调度算法的是(  )

A. 先来先服务(FCFS) B. 短作业优先(SJF) ✅ C. 最高响应比优先(HRRN) D. 以上都不对

  • 解释 Explanation:
    • 最高响应比优先(HRRN)是动态优先权调度算法,它的优先级随着作业等待时间的增加而提高。优先级 = (等待时间 + 服务时间) / 服务时间。
    • FCFS 和 SJF 是静态优先级调度方法,不随时间动态变化。

8.在可变分区存储管理中,最先适应分配算法要求对空闲区表项按( )进行排列。

A. 地址从大到小 ✅ B. 地址从小到大 C. 尺寸从大到小 D. 尺寸从小到大

  • 解释 Explanation:
    • 最先适应算法(First Fit)从低地址开始寻找第一个足够大的空闲区,因此需要按地址从小到大排列空闲区表项,以便尽快找到合适的分区。

9.若系统中有五个并发进程涉及某个相同的变量A,则与变量A的相关临界区有( )。

A. 1个 B. 3个 C. 4个 ✅ D. 5个

  • 解释 Explanation:
    • 每个进程访问共享变量 A 的代码段都必须被视为临界区,因此总共有 5 个与变量 A 相关的临界区(每个进程一个)。

10.进程所请求的一次输入过程结束后,将使进程状态从( )

A. 运行态变为就绪态 B. 运行态变为等待态 C. 就绪态变为运行态 ✅ D. 等待态变为就绪态

  • 解释 Explanation:
    • 进程在请求 I/O 后会进入等待态(waiting),当输入操作完成后,表示资源就绪,进程被唤醒,状态变为就绪态(ready),等待 CPU 调度重新运行。

11.一种既有利于短小作业又兼顾到长作业的作业调度算法是( )

A. 先来先服务(FCFS) B. 轮转(RR) ✅ C. 最高响应比优先(HRRN) D. 均衡调度

  • 解释 Explanation(中英文)

    • 最高响应比优先(HRRN,Highest Response Ratio Next) 能动态调整优先级,使等待时间长的作业优先级提升,从而兼顾长作业,同时短作业响应比本身高,也能快速执行。
    • HRRN 响应比 = (等待时间 + 服务时间) / 服务时间。

12.存储管理中的拼接技术可以( )

✅ A. 集中空闲区 B. 增加主存容量 C. 提高执行速度 D. 加速地址转换

  • 解释 Explanation(中英文)

    • 拼接(compaction) 是把内存中的零碎空闲块合并成一个连续大空闲块,从而减少内存碎片。
    • 它不会改变主存大小,但有助于更有效地使用内存空间。

13.虚拟存储管理策略可以( )

A. 扩大物理内存容量 B. 扩大物理外存容量 ✅ C. 扩大逻辑内存容量 D. 扩大逻辑外存容量

  • 解释 Explanation(中英文)

    • 虚拟存储器允许程序使用比实际物理内存更大的逻辑地址空间。程序在不同时刻只需加载一部分页面入内存即可运行,从而逻辑上扩大内存容量
    • It expands logical memory, not physical.

14.分页式存储管理中,地址转换工作是由( )完成的。

✅ A. 硬件 B. 地址转换程序 C. 用户程序 D. 装入程序

  • 解释 Explanation(中英文)
    • 分页系统中,虚拟地址到物理地址的转换通常由**硬件单元(MMU, Memory Management Unit)**自动完成,无需程序干预。
    • 软件仅初始化页表,实际访问时是硬件查页表。

15.若系统中有八台绘图仪,有每个进程均需要使用三台,规定每个进程一次仅允许申请一台,则至多允许( )个进程参于竞争,而不会发生死锁。

✅ C. 3

  • 答案:C. 3
    解释:
    根据银行家算法,最大安全进程数 \(n\) 需满足:
    \[ n \times (3-1) \leq 8 - 1 \quad \Rightarrow \quad 2n \leq 7 \quad \Rightarrow \quad n = 3 \] • 总资源需求:若3个进程各持有2台,剩余2台可满足其中一个进程的最后一台请求,避免死锁。

• 若允许4个进程:总分配 \(4 \times 2 = 8\) 台,剩余0台,所有进程因无法获得第三台而死锁。


16.在以下存储管理方案中,不适用于多道程序设计系统的是(  )

✅ A. 单用户连续分配 B. 段式分区分配 C. 段页式分区分配 D. 页式存储管理

  • 解释 Explanation(中英文)
    • 单用户连续分配(Single-user contiguous allocation) 仅支持单个程序运行,不能实现内存共享,因此不适用于多道程序设计(multi-programming)系统。
    • 其余三种内存管理方式都支持多个程序共享内存空间。

17.UNIX系统中,进程调度采用的技术是( )

A. 时间片轮转 B. 先来先服务 C. 静态优先数 ✅ D. 动态优先数

  • 解释 Explanation(中英文)
    • UNIX 系统采用的是 动态优先级调度(Dynamic Priority Scheduling),通过调整进程的“nice 值”和 CPU 占用率,动态改变优先级,兼顾公平性与响应性。
    • This improves both interactivity and throughput.

18.一作业进入内存后,则所属该作业的进程初始时处于( )状态。

✅ B. 就绪(Ready)

  • 解释 Explanation(中英文)
    • 作业进入内存但尚未获得 CPU,则对应进程处于就绪状态,等待调度器分配 CPU。
    • 只有当它真正开始执行后才进入运行态(Running)。

19.UNIX系统中,文件存储器的管理采用的是( )

✅ C. 成组链接法(Grouped Linking Method)

  • 解释 Explanation(中英文)
    • UNIX 文件系统使用 成组链接法(grouped free list) 来管理空闲磁盘块,即将空闲块成组地链接,减少查找开销。
    • This method optimizes performance for large file systems.

20.在虚拟页式存储管理系统中,当访问主存中的一条指令或数据时( )

✅ D. 最多访问两次主存(At most 2 memory accesses)

  • 解释 Explanation(中英文)
    • 在页式系统中,一次内存访问通常包括:
      1. 访问页表(如果没有 TLB 缓存);
      2. 访问实际的数据或指令地址;
    • 所以最多需要两次主存访问(一次查页表,一次取数据)。

填空题


1.操作系统的存储保护包括______和______。

✅ 答案:边界保护 和 访问权限保护 英文: Boundary protection and access rights protection 解释:

  • 边界保护用于防止访问越界;访问权限保护用于防止非法读写他人内存区域。

2.死锁的四个必要条件是__________、__________、不可抢占和循环等待。

✅ 答案:互斥、请求保持 英文: Mutual exclusion, Hold and wait, No preemption, Circular wait 解释:

  • 死锁发生的必要条件是四个,缺一不可。

3.在 UNIX 系统中文件分为三类,它们是________和________和特殊文件。

✅ 答案:普通文件、目录文件 英文: Regular files, Directory files, and Special files 解释:

  • 普通文件存储数据,目录文件组织结构,特殊文件映射设备。

4.在存储器管理中,页面大小由______确定,段的长度由______确定。

✅ 答案:操作系统、用户程序 英文: Page size is set by the OS; Segment size is set by the user program 解释:

  • 页面是固定大小,由系统控制;段是逻辑单位,由程序需要决定。

5.设备分为内部设备和外部设备,内部设备包括________和________。

✅ 答案:内存、CPU寄存器 英文: Memory and CPU registers 解释:

  • 内部设备不需要 I/O 通信,外部设备如硬盘、打印机等需外设驱动。

6.进程的静态实体由____、____和进程控制块PCB三部分组成。

✅ 答案:程序、数据 英文: Program, Data, and Process Control Block (PCB) 解释:

  • 程序是代码,数据是变量,PCB 是进程的控制信息。

7.进程的三种基本状态是就绪态、****、******。**

✅ 答案:运行态、等待态 英文: Ready, Running, and Waiting (or Blocked) 解释:

  • 就绪:等待 CPU;运行:占用 CPU;等待:等待资源或事件。

8.在响应比最高者优先的作业调度算法中,当各个作业等待时间相同,______将得到优先调度;当各个作业运行的时间相同时,______得到优先调度。

✅ 答案:运行时间短的作业、等待时间长的作业 英文:

  • When wait times are equal, the job with shorter service time is scheduled first.
  • When service times are equal, the job with longer wait time is prioritized. 解释:
  • 响应比 =(等待时间 + 服务时间)/ 服务时间

9.并发进程中涉及到______的程序段称为临界区,两个进程同时进入相关的临界区会造成______的错误。

✅ 答案:共享资源、竞态条件 英文: Critical section involves shared resources; simultaneous access causes race condition. 解释:

  • 临界区是访问共享资源的代码区域;未加互斥控制会引发数据错误。

10.UNIX 系统中文件次部主要包括______、______两部分。

✅ 答案:i 节点(i-node)、目录项 英文: i-node and directory entry 解释:

  • i-node 存储元数据(权限、位置等),目录项保存文件名和 i-node 号。

判断题


1. I/O传输中采用通道方式后不再需要CPU的参与。

❌ 错误(False) 英文:Even with channel-based I/O, CPU participation is still required. 解释: 通道可以减轻CPU负担,实现异步I/O,但仍需要CPU来初始化通道、启动I/O请求并处理中断。


2. 系统栈的数量由系统进程数量决定的。

✅ 正确(True) 英文:The number of system stacks depends on the number of system processes. 解释: 每个内核线程或进程在内核态下需要一个系统栈,用于保存调用过程,因此栈数与进程数直接相关。


3. 进程处于运行状态时,其程序一定占有处理机执行。

✅ 正确(True) 英文:When a process is in the running state, it must be executing on the CPU. 解释: “运行态”定义本身就是正在使用CPU资源,所以它一定正在执行。


4. 内存容量确定时,页面越小则页面数越多,越不容易出现颠簸(抖动)。

❌ 错误(False) 英文:Smaller page size can increase page faults, possibly leading to thrashing. 解释: 页面太小会使页表变大,管理开销增加,增加缺页率,从而更容易发生抖动(thrashing)。


5. 一个进程执行了管程中的唤醒操作后,一定会进入紧急等待队列。

❌ 错误(False) 英文:A process performing a wake-up in a monitor does not necessarily enter the urgent wait queue. 解释: 执行唤醒操作的是当前执行管程的进程,它不会自己进入等待队列,而是可能唤醒其他等待的进程。


简答题


1. 发生中断后,若中断处理程序是用户规定的,则系统怎样处理?

英文:When an interrupt occurs and the handler is user-defined, how does the system respond?

答: 系统会保存当前进程的上下文(程序计数器、寄存器等),然后转到用户注册的中断处理程序执行;处理完后,系统再恢复上下文,返回原程序继续执行。

解释: 为了支持用户自定义中断,系统需要先做好上下文保护和安全性检查,然后跳转执行用户的中断服务例程(ISR),最后再通过中断返回(IRET)继续原程序。


2. 页式虚拟存储管理中,访问内存次数有几种情况,原因是什么?

英文:In paged virtual memory, what are the different memory access situations and why?

答: 有两种情况:

  1. 若所访问页在主存中,仅访问主存一次。
  2. 若页不在主存中(缺页),需访问辅存,将页调入主存,再访问一次主存,共访问两次或更多。

解释: 这是由虚拟地址到物理地址的映射机制决定的,缺页处理需要加载页表和页面,从而影响访问次数。


3. 虚拟设备与缓冲技术的区别?

英文:What is the difference between virtual devices and buffering techniques?

答:

  • 虚拟设备是将一个物理设备模拟为多个逻辑设备(如打印机虚拟成多个任务队列)。
  • 缓冲技术是通过设置内存缓冲区来实现数据的临时存储,提高I/O效率。

解释: 虚拟设备强调设备共享与虚拟化;缓冲技术强调数据流的效率与速度控制,两者目的不同。


4. 死锁的四个必要条件,什么情况下可认为是充要条件?

英文:What are the four necessary conditions for deadlock, and when are they sufficient and necessary?

答: 四个必要条件是:

  1. 互斥(Mutual Exclusion)
  2. 请求与保持(Hold and Wait)
  3. 不可剥夺(No Preemption)
  4. 循环等待(Circular Wait)

当四个条件同时满足时,死锁一定会发生,所以这四个条件构成死锁发生的充要条件

解释: 这意味着只要打破任意一个条件,就可以防止死锁的发生。


模拟页面置换算法


题目 / Problem

在一个采用页式虚拟存储管理的系统中,有一个用户作业,它依次要访问的逻辑地址序列是:

1
150,200,110,55,450,180,301,422,210,117

分配给该进程的主存空间共 300 字节,每页大小为 100 字节。回答:

  1. 按 FIFO 调页算法将产生多少次缺页中断?依次淘汰的页号为哪些?缺页中断率是多少?
  2. 按 LRU 调页算法将产生多少次缺页中断?依次淘汰的页号为哪些?缺页中断率是多少?

预备工作 / Preparation

  1. 页号转换:页号 = ⌊地址/100⌋

    1
    2
    地址:150 200 110  55 450 180 301 422 210 117
    页号: 1 2 1 0 4 1 3 4 2 1

    访问序列 P = [1, 2, 1, 0, 4, 1, 3, 4, 2, 1]

  2. 物理帧数 = 300 字节 ÷ 100 字节/页 = 3 帧

  3. 访问总次数 = 10


(1)FIFO 算法

  • 缺页中断数(Page Faults):7 次
  • 依次淘汰的页号(Eviction Sequence):1, 2, 0, 4
  • 缺页中断率(Fault Rate) = 7 / 10 = 0.7 (70%)

详细过程示意

访问 帧内容(装入后) 缺页? 淘汰页号
1 [1,–,–] Y
2 [1,2,–] Y
1 [1,2,–] N
0 [1,2,0] Y
4 [4,2,0] Y 1
1 [4,1,0] Y 2
3 [4,1,3] Y 0
4 [4,1,3] N
2 [2,1,3] Y 4
1 [2,1,3] N

(2)LRU 算法

  • 缺页中断数(Page Faults):7 次
  • 依次淘汰的页号(Eviction Sequence):2, 0, 1, 3
  • 缺页中断率(Fault Rate) = 7 / 10 = 0.7 (70%)

详细过程示意

访问 帧内容(最近使用顺序 →) 缺页? 淘汰页号
1 [1] Y
2 [1,2] Y
1 [2,1] N
0 [2,1,0] Y
4 [1,0,4] Y 2
1 [0,4,1] N
3 [4,1,3] Y 0
4 [1,3,4] N
2 [3,4,2] Y 1
1 [4,2,1] Y 3

中英文总结 / Summary

算法 缺页中断数 淘汰页号 缺页率
FIFO 7 1, 2, 0, 4 0.7 (70%)
LRU 7 2, 0, 1, 3 0.7 (70%)

磁盘调度算法

某磁盘有400个磁道,某一时刻,磁盘的请求序列为:50,100,300,80,20,150,200,70,按电梯算法SCAN及单向扫描算法C-SCAN计算引臂移动量


1. SCAN(电梯算法)

执行顺序

  1. 从 50 开始,向增大方向依次服务在 50 以上的请求: 70 → 80 → 100 → 150 → 200 → 300
  2. 到达最后一个请求 300 后,向减小方向折返,服务剩余在 50 以下的请求: 20

计算移动量

  • 从 50 到 300:|300 − 50| = 250
  • 从 300 折返到 20:|300 − 20| = 280
  • 总移动量 = 250 + 280 = 530 轨道

2. C-SCAN(循环扫描算法)

执行顺序

  1. 从 50 开始,向增大方向依次服务在 50 以上的请求: 70 → 80 → 100 → 150 → 200 → 300
  2. 到达最大磁道 399 后,不折返,而是跳转(不计移动)到最小磁道 0,再向增大方向继续服务: 20

计算移动量

  1. 50 → 300:|300 − 50| = 250
  2. 300 → 399(扫尾到末端):|399 − 300| = 99
  3. 末端“跳转”回 0:跳转过程不计轨道移动
  4. 0 → 20:|20 − 0| = 20
  • 总移动量 = 250 + 99 + 20 = 369 轨道

注意:C-SCAN 中从 399 跳转到 0 的过程不计算在移动量内。


中英文对照总结

算法 服务序列 总移动量
SCAN 50→70→80→100→150→200→300→20 530 轨道
C-SCAN 50→70→80→100→150→200→300→(→399 跳→0)→20 369 轨道

English Summary:

  • SCAN moves out to the furthest request then reverses; total movement = 530 tracks.
  • C-SCAN treats the disk as circular: moves out, jumps back to 0, then continues; total counted movement = 369 tracks.

进程PV问题

假设有4个进程P1,P2,P3,P4共享同一缓冲区(20个存储单元),进程P1读取数据写入缓冲区,P2、P3从缓冲区读取P1写入的数据进行不同的运算,将结果分别写入缓冲区后保存P1数据的存储单元可以释放,进程P4将P2、P3的运算结果读取后进行综合运算结果输出,同时释放存储单元。

请用PV操作,写出它们的并发生产过程(开始时缓冲区为空)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/* 信号量定义 */
Semaphore empty = 20, // 缓冲区空单元数
rawAvail = 0, // P1 写入的“原始数据”可用单元数
res2Avail = 0, // P2 生成的结果二可用单元数
res3Avail = 0, // P3 生成的结果三可用单元数
mutex = 1; // 访问缓冲区的互斥信号量

/* 环形缓冲区和索引 */
struct Cell {
Data raw; // P1 写入的原始数据
Data2 r2; // P2 写入的结果
Data3 r3; // P3 写入的结果
int done; // 已由 P2、P3 完成的计数
} buffer[20];

int in = 0, out = 0; // 缓冲区写/读索引

/* 生产者 P1:读取外部数据,写入 raw 字段 */
Process P1() {
Data d;
while (get_next_input(&d)) {
P(empty);
P(mutex);
buffer[in].raw = d;
buffer[in].done = 0; // 重置阶段完成计数
in = (in + 1) % 20;
V(mutex);
V(rawAvail);
}
}

/* 中间处理者 P2:从 rawAvail 中消费,写入 r2 */
Process P2() {
Data d;
Data2 r2;
while (true) {
P(rawAvail);
P(mutex);
d = buffer[out].raw;
V(mutex);

r2 = compute2(d); // 不同运算阶段

P(mutex);
buffer[out].r2 = r2;
if (++buffer[out].done == 2) { // P2、P3 都完成时
V(empty); // 释放该单元
V(res2Avail); // 通知 P4 其结果可取
V(res3Avail); // P4 同时还要取 P3 的结果
}
V(mutex);
}
}

/* 中间处理者 P3:从 rawAvail 中消费,写入 r3 */
Process P3() {
Data d;
Data3 r3;
while (true) {
P(rawAvail);
P(mutex);
d = buffer[out].raw;
V(mutex);

r3 = compute3(d);

P(mutex);
buffer[out].r3 = r3;
if (++buffer[out].done == 2) {
V(empty);
V(res2Avail);
V(res3Avail);
}
V(mutex);
}
}

/* 汇总者 P4:获得 P2、P3 的结果,做最终处理 */
Process P4() {
Data2 r2; Data3 r3;
while (true) {
P(res2Avail);
P(res3Avail);
P(mutex);
r2 = buffer[out].r2;
r3 = buffer[out].r3;
out = (out + 1) % 20;
V(mutex);

final = combine(r2, r3);
output(final);
}
}

解释(中英文)

  1. empty:跟踪缓冲区剩余空单元数,P1 写前 P(empty),P2/P3 完成后 V(empty) 释放单元。
  2. rawAvail:P1 写完原始数据后 V(rawAvail),P2 和 P3 各自 P(rawAvail) 取走同一单元的原始数据进入自己的处理阶段。
  3. done 计数:每个单元有个 done 计数,P2/P3 完成后各自 ++done,当 done==2 时说明两阶段都做完,才释放该单元并通知 P4。
  4. res2Avail / res3Avail:P2/P3 在 done==2 时都做一次 V(res2Avail)V(res3Avail),确保 P4 能同时 P(res2Avail)P(res3Avail) 取到同一单元的两个结果。
  5. mutex:保护对缓冲区数组和索引的互斥访问。

这样,4 个并发进程在同一个 20 单元缓冲区上,安全地完成了“P1→P2/P3→P4”的三级流水线处理。

进程管程问题

某汽车站售票厅,有四个窗口,共有两个班次的车票出售,任何时刻最多可容纳50名顾客,当营业厅中少于50名顾客时,则厅外的顾客可进入等待,否则需在外面等待。按顾客进入顺序发号,窗口按号码顺序服务;顾客进入后若没有所需车票或先进入顾客已经能够买光车票,则直接离开售票厅。门口一次只能进出一位顾客。 请用管程实现顾客的行为。给出问题,答案和解释


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// C++-风格伪代码

// 常量定义
const int MAX_INSIDE = 50; // 厅内最多容纳顾客数
const int WINDOW_COUNT = 4; // 窗口数
const int CLASS_COUNT = 2; // 班次(票种)数

// 管程定义
monitor TicketOffice {
// 共享状态
int insideCount = 0; // 当前厅内顾客数
int nextTicketNo = 1; // 给进入顾客发号(递增)
int serveNo = 1; // 当前轮到的票号
int tickets[CLASS_COUNT]; // 各班次剩余票数

// 条件队列
condition outsideQ; // 厅外排队
condition windowQ; // 厅内按票号排队

// 初始化:传入每个班次的初始票数
TicketOffice(int initTickets[]) {
for (int i = 0; i < CLASS_COUNT; i++)
tickets[i] = initTickets[i];
}

// (1)顾客进入售票厅并排号
int enter() {
int myNo = nextTicketNo++;
// 厅内若已满,先在 outsideQ 等待
while (insideCount >= MAX_INSIDE)
outsideQ.wait();
insideCount++;
// 进厅后还要按号码排队
while (serveNo != myNo)
windowQ.wait();
return myNo;
}

// (2)顾客到窗口尝试购票,ticketClass ∈ {0,1}
bool buy(int ticketClass) {
if (tickets[ticketClass] <= 0) {
// 无票可买,直接返回失败
return false;
}
// 有票,售出一张
tickets[ticketClass]--;
return true;
}

// (3)顾客结束并离开:释放窗口和厅内名额,唤醒下一个
void leave(int myNo) {
// 增加下一号可服务
serveNo++;
windowQ.signal(); // 通知下一个号码顾客
insideCount--;
outsideQ.signal(); // 厅外若有人可进
}
};

// 顾客进程(行为描述)
process Customer(int desiredClass, TicketOffice &office) {
// 1. 进厅取号并排队
int myNo = office.enter();

// 2. 排号到自己后,到窗口尝试买票
bool got = office.buy(desiredClass);

// 3. 无票或已售完则离开;否则也离开(假设只买一张)
if (!got) {
// 可选:打印“对不起,票已售完”
} else {
// 可选:打印“购票成功”
}
office.leave(myNo);
}

中英文解释 / Explanation

  1. enter() — 进厅与排队
    • 厅外等待:若 insideCount ≥ MAX_INSIDE,顾客在 outsideQ 上等待。
    • 排号服务:使用 nextTicketNo 给每位顾客一个递增号码 myNo,厅内顾客按该号码在 windowQ 上等待,保证“窗口按号码顺序服务”。
  2. buy() — 尝试购票
    • 检查对应班次剩余票数 tickets[ticketClass]
    • 若没有则返回 false,顾客直接离开;否则将票数减一并返回 true
  3. leave() — 离开与唤醒
    • 更新 serveNo,然后调用 windowQ.signal() 唤醒号码队列中的下一个顾客。
    • 减少 insideCountsignal() outsideQ,让厅外顾客进厅。
  4. 互斥性
    • 管程内部操作天然互斥,不需要额外的锁。
  5. 公平性
    • 顾客“按进入顺序发号”与“按号码顺序服务”保证了公平;“厅外—厅内”两级等待保证容量限制。

这样,用一个管程就能清晰地描述整个售票厅中顾客的并发行为:入厅取号、排队等候、购票检测、离开释放,严格满足题意中“最多50人”“按号服务”“无票即离开”“门口一次一人”等约束。