Skip to content

2014年 408 操作系统 第 47 题

操作系统2014年综合题8分

题目

系统中有多个生产者进程和多个消费者进程,共享一个能存放 1000 件产品的环形缓冲区(初始为空)。

约束:

  • 缓冲区未满时,生产者进程可以放入其生产的一件产品;否则等待
  • 缓冲区未空时,消费者进程可以从缓冲区取走一件产品;否则等待
  • 要求一个消费者进程从缓冲区连续取出 10 件产品后,其他消费者进程才可以取产品

请使用信号量 P、V 操作实现进程间的互斥与同步,要求写出完整的过程,并说明所用信号量的含义和初值。

解析

关系拆解

标准生产者-消费者部分

约束信号量初值
缓冲区互斥buffer_mutex1
缓冲区空位empty1000
缓冲区已有产品数full0

本题特殊约束

"一个消费者连续取 10 件后,其他消费者才能取"

这相当于消费者之间对"取产品序列"的互斥——一旦某个消费者开始取,他要连续占用消费权 10 次,期间其他消费者不能插队。

需要新增 consumer_mutex 信号量:

  • 消费者进入循环 10 次取产品之前 P(consumer_mutex)
  • 取完 10 次之后 V(consumer_mutex)
信号量初值用途
consumer_mutex1"连续取 10 次"的消费者间互斥

信号量与代码

c
semaphore consumer_mutex = 1;     // 消费者间"连续取 10 次"互斥
semaphore buffer_mutex   = 1;     // 缓冲区单次访问互斥
semaphore empty          = 1000;  // 缓冲区空位数
semaphore full           = 0;     // 缓冲区产品数

Producer() {
    while (true) {
        生产产品;
        P(empty);                  // 等空位
        P(buffer_mutex);           // 占用缓冲区
        将产品放入缓冲区;
        V(buffer_mutex);           // 让出缓冲区
        V(full);                   // 通知消费者:又多一件
    }
}

Consumer() {
    while (true) {
        P(consumer_mutex);         // ★ 拿到"独占连续取 10 次"权限
        for (int i = 0; i < 10; i++) {
            P(full);               // 等有产品
            P(buffer_mutex);       // 占用缓冲区
            从缓冲区取出产品;
            V(buffer_mutex);       // 让出缓冲区
            V(empty);              // 通知生产者:多出空位
            消费产品;              // 消费可以放在临界区外
        }
        V(consumer_mutex);         // ★ 让出"连续取"权限
    }
}

信号量含义说明(答题必写)

信号量初值含义
consumer_mutex1消费者之间"连续取 10 件"的串行权
buffer_mutex1缓冲区单次操作互斥(生产者和消费者都用)
empty1000缓冲区空闲位数
full0缓冲区已有产品数

易错点

编者注(题面陷阱 + 关键技巧)

  1. empty 初值是 1000,不是 0——题目说缓冲区初始为空,所以"空位数 = 1000","产品数 = 0"。初值不要搞反empty 跟"空"位数挂钩、初值 = 容量;full 跟"已有"件数挂钩、初值 = 0。

  2. consumer_mutex 必须包在 for 循环外

    • 正确P(consumer_mutex); for (i=0; i<10) {取一件}; V(consumer_mutex); —— 消费者 A 取 10 件期间,B 一直在 P(consumer_mutex) 上阻塞
    • 错误for (i=0; i<10) { P(consumer_mutex); 取; V(consumer_mutex); } —— 这样 A、B 会"轮流"取产品,每次只取 1 件,完全不满足"连续 10 件"
  3. buffer_mutexconsumer_mutex 必须分开——两者作用不同:

    • buffer_mutex:保护缓冲区数据结构(环形队列指针),生产者和消费者都用,单次操作互斥
    • consumer_mutex:保护取产品的连续性,只有消费者用,10 次操作互斥

    用一个信号量同时管,要么连续 10 次会让生产者也卡住(无法生产),要么生产者能插队但消费者无法连续——两种坏处都有

  4. P(empty) 必须在 P(buffer_mutex) 之前——经典死锁规避(与 2009-45 同理)。如果反过来,生产者拿了 mutex 但 empty=0,会死锁。

  5. 若题目改成"缓冲区至少有 10 件产品消费者才能开始取"——评分说明说这种理解给 6 分(不全对)。正确理解是"任何时候只要缓冲区非空消费者就能取,但取要连续 10 次才让出"。本题不是"等到 10 件齐了再取"。看清"连续取出"四个字。

  6. 生产者之间不需要单独互斥信号量——buffer_mutex 已经管住了多生产者之间的冲突;不要再加 producer_mutex,否则降低并发度且评分会扣"未做到尽可能少"的分。

最后更新:

🎬 可视化演示
加载中...

提示:可在可视化区直接操作播放、步进、修改参数