Skip to content

条件变量

考情分析

管程和条件变量在 408 真题中偶有涉及,属于 🔥 中低频考点,但近年考查频率有上升趋势。

信号量 PV 操作写反就死锁、漏写就数据错乱——这种手动挡太容易翻车了。管程的思路是把共享数据和操作封装在一起,由编译器自动保证互斥,程序员只需要关心同步逻辑。

比信号量更安全的同步机制

信号量机制虽然强大,但编程容易出错:P/V 操作顺序写反会导致死锁,漏写会导致互斥失效。管程(Monitor)的目标是提供一种更高级、更安全的同步机制。

管程的定义

管程是一种封装了共享数据及其操作的同步机制,由以下部分组成:

  1. 共享数据结构(管程内部的变量)
  2. 一组过程(对共享数据的操作函数)
  3. 初始化语句
  4. 管程名称
monitor ProducerConsumer {
    // 共享数据
    int buffer[N];
    int count = 0;

    // 条件变量
    condition notFull, notEmpty;

    // 过程
    procedure insert(item) { ... }
    procedure remove() { ... }
}

管程的关键特性

特性说明
互斥访问同一时刻最多只有一个进程在管程内执行(编译器自动保证)
封装性共享数据只能通过管程提供的过程访问
条件等待通过条件变量实现进程的等待和唤醒

条件变量

条件变量(Condition Variable)是管程中用于进程等待/唤醒的机制。每个条件变量对应一个等待队列。

两个操作:

操作说明
wait(c)当前进程在条件 c 上阻塞,释放管程的使用权
signal(c)唤醒在条件 c 上等待的一个进程

条件变量 vs 信号量

条件变量的 waitsignal 与信号量的 P/V 不同

  • 条件变量没有「值」的概念,signal 时如果没有等待进程,该信号就丢失了
  • 信号量的 V 操作无论是否有等待进程,都会使 value+1(信号被记录)

用管程解决生产者-消费者问题

monitor ProducerConsumer {
    int buffer[N];
    int count = 0;
    condition notFull, notEmpty;

    procedure insert(item) {
        if (count == N)
            wait(notFull);       // 缓冲区满,等待
        buffer[count] = item;
        count++;
        signal(notEmpty);        // 通知消费者
    }

    procedure remove() {
        if (count == 0)
            wait(notEmpty);      // 缓冲区空,等待
        item = buffer[count - 1];
        count--;
        signal(notFull);         // 通知生产者
        return item;
    }
}

// 生产者进程
producer() {
    while (true) {
        item = produce();
        ProducerConsumer.insert(item);
    }
}

// 消费者进程
consumer() {
    while (true) {
        item = ProducerConsumer.remove();
        consume(item);
    }
}

对比信号量方案,管程方案不需要手动 P/V,互斥由管程自动保证,更不容易出错。

Hoare 管程 vs Mesa 管程

当一个进程执行 signal 唤醒另一个进程时,两个进程都想在管程内执行,怎么处理?

类型处理方式特点
Hoare 管程signal 后立即让出管程,被唤醒进程继续执行条件保证成立,但切换频繁
Mesa 管程signal 后继续执行,被唤醒进程稍后竞争进入被唤醒时条件可能不满足,需用 while 循环重检

Mesa 管程中需要将 if 改为 while

// Mesa 管程
procedure insert(item) {
    while (count == N)      // 用 while 而非 if
        wait(notFull);
    ...
}

考研高频考点

  • 🔥🔥 管程的定义和特性(封装+互斥+条件变量)
  • 🔥🔥 条件变量与信号量的区别(有无值的概念)
  • 🔥 管程中同一时刻只允许一个进程执行
  • 🔥 Hoare 管程 vs Mesa 管程的区别

有了信号量和管程这些同步工具,接下来用它们解决经典问题。下一篇从最核心的生产者-消费者问题开始。

真题练习

相关真题(2题)

2018Q28选择题2分

条件变量wait:无条件阻塞当前进程并加入等待队列

2016Q32选择题2分

管程:既能实现互斥也能实现同步