#GPLT0008. 【GPLT 2026】L1-8 生产者-消费者问题

【GPLT 2026】L1-8 生产者-消费者问题

题目描述

江月诗最近在学习《计算机操作系统》,学到「生产者 - 消费者问题」时感觉头都大了。为了巩固理解,他决定抛开复杂的并发机制,只用一个纯顺序执行的模拟题来理清数据的存取流程。

请你模拟一个容量为 nn 的环形缓冲区(可以理解为一个长度为 nn 的数组),每个格子只能存放 11 个数据,格子编号从 00n1n-1

系统内部维护两个记录位置的指针,初始时均指向 00 号格子:

  • 入队指针:负责指示下一个货物应该放在哪个格子。
  • 出队指针:负责指示下一次应该从哪个格子取走货物。

现在给定一系列按先后顺序发生的操作,分为以下两种:

  • 生产者(P):编号为 xx 的生产者尝试放入 11 个数据。
    • 成功条件:缓冲区内至少还有 11 个空位。
    • 执行动作:将数据放入「入队指针」所在的格子,随后「入队指针」向后移动一位(若越过数组末尾,则循环回到 00 号格子)。
    • 失败处理:如果缓冲区已满,该操作直接失败并被丢弃(不会排队等待)。
  • 消费者(C):编号为 yy 的消费者尝试取出 11 个数据。
    • 成功条件:缓冲区内至少有 11 个数据。
    • 执行动作:将数据从「出队指针」所在的格子取出(该格子变为空位),随后「出队指针」向后移动一位(若越过数组末尾,则循环回到 00 号格子)。
    • 失败处理:如果缓冲区是空的,该操作直接失败并被丢弃(不会排队等待)。

请你模拟整个按序执行的过程,并输出每次操作的结果以及最终的统计信息。

输入格式

第一行:两个正整数 nnmm2n201m1002 \leq n \leq 20,1 \leq m \leq 100),分别表示缓冲区容量和操作总数。

接下来 mm 行:每行一个操作,格式为 P xC y,其中 1x,y1001\leq x,y\leq 100,代表生产者或消费者的编号。

输出格式

对于每一步操作:

  • 如果操作成功:输出一行 [操作类型] [编号] success,并在紧接着的下一行输出当前缓冲区的所有格子状态(用空格分隔的 nn 个数字,00 表示空位,11 表示有数据,严格按格子编号 00n1n-1 的顺序输出)。
  • 如果操作失败:输出一行 [操作类型] [编号] fail(失败时不需要输出缓冲区状态)。

所有操作结束后,最后输出三行统计信息:

  1. Remain: [剩余数据数量]
  2. Producer: [每个成功的生产者编号:成功次数](按编号从小到大升序排列,用空格分隔;一次都没成功过的生产者不输出)。
  3. Consumer: [每个成功的消费者编号:成功次数](按编号从小到大升序排列,用空格分隔;一次都没成功过的消费者不输出)。

输入样例

3 7
P 1
P 2
P 3
P 4
C 1
C 2
C 3

输出样例

P 1 success
1 0 0
P 2 success
1 1 0
P 3 success
1 1 1
P 4 fail
C 1 success
0 1 1
C 2 success
0 0 1
C 3 success
0 0 0
Remain: 0
Producer: 1:1 2:1 3:1
Consumer: 1:1 2:1 3:1

样例解释

  1. 缓冲区容量为 3,前 3 个生产者依次放入数据,缓冲区被填满,状态依次变为 1 0 0 -> 1 1 0 -> 1 1 1
  2. 4 个生产者尝试放入数据时缓冲区已满,操作失败。
  3. 3 个消费者依次取出数据,分别从 0、1、2 号格子取走,缓冲区最终清空。
  4. 最终缓冲区剩余数据为 0。统计得到 1、2、3 号生产者和 1、2、3 号消费者都各成功执行了 1 次。