跳转至

进程同步与互斥——PV信号量操作专题

前言

进程同步与互斥的设计题在考试中分数占比较重(15分),但是题目难度较其它题来说个人认为更大。题目大多以经典的同步互斥问题为框架,换汤不换药地进行出题,所以如果对经典地几个同步互斥题熟练掌握,再对于题目加以剖析,这类题就会显得更为套路了。

几个经典的同步与互斥问题

1. 生产者-消费者问题

题目设定为,存在一个缓冲区,生产者每次可以生产一个产品加入缓冲区,而消费者每次可以从缓冲区中取出一个产品进行消费,生产者消费者不能同时对缓冲区进行操作,缓冲区可能有上限,如果存在上限,则当缓冲区满时生产者无法将产品加入缓冲区,需要等待缓冲区存在空位才能将产品放入。如果缓冲区目前没有产品,消费者就需要等待缓冲区中存在产品后再进行消费。

N空位

semaphore mutex = 1; // 缓冲区保护
semaphore full = 0; // 缓冲区产品数
semaphore empty = N; // 缓冲区空位数

process producer {
    P(empty);
    P(mutex);
    V(full);
    V(mutex);
}

process comsumer {
    P(full);
    P(mutex);
    V(empty);
    V(mutex);
}

理发师问题

理发师问题本身可以用生产者消费者模型刻画。题面如下:

理发店有一位理发师,一把理发椅和N把供等候理发的顾客坐的椅子。如果没有顾客,则理发师便在理发椅上睡觉,当一个顾客到来时,他必须先叫醒理发师,如果理发师正在理发时又有顾客到来,则如果有空椅子可坐,他们就坐下来等。如果没有空椅子,他就离开。

这个题面第一次看会觉得有点陌生,下面分析一下题面。

理发店有一位理发师(消费者),一把理发椅和N把供等候理发的顾客坐的椅子(缓冲区)。如果没有顾客(产品),则理发师便在理发椅上睡觉(等待产品),当一个顾客到来时(生产者生产了一个产品),他必须先叫醒理发师,如果理发师正在理发(消费产品)时又有顾客到来(产品被生产出来),则如果有空椅子可坐(缓冲区有空位),他们就坐下来等。如果没有空椅子(缓冲区无空位),他就离开(不等待)。

再剖析地更直接点就是

存在一个缓冲区,生产者每次可以生产一个产品加入缓冲区,而存在一个消费者每次可以从缓冲区中取出一个产品进行消费,生产者消费者不能同时对缓冲区进行操作,缓冲区只能存放N个产品,则当缓冲区满时生产者无法将产品加入缓冲区,直接放弃该产品。如果缓冲区目前没有产品,消费者就会等待缓冲区中存在产品后再进行消费,一旦存在产品,消费者就会开始进行消费。

其中

  • 生产者:使得顾客进来的机制本身
  • 产品:顾客
  • 消费者:理发师
  • 缓冲区:等待椅
  • 消费:理发
  • 等待:理发师睡觉

这个生产者-消费者模型与之前相比,最大的不同在于生产者不会进行等待,会直接结束进程,所以这里对于空位资源不能使用信号量机制,它不是进程执行必须的资源,而是判断的条件。于此同时,这里的消费者只有一个,但是是会不断进行消费的,生产者生产出的产品存在被消费的动作。

对于这道题的生产者-消费者模型,代码如下

semaphore full = 0; // 产品数
semaphore mutex = 1; // 保护缓冲区
semaphore signal = 0; // 唤醒生产者
int empty = N; // 空位数

process comsumer {
    while (true) {
        P(full);
        P(mutex);
        empty++;
        V(signal);
        V(mutex);
        消费
    }
}

process producer {
    P(mutex);
    if (empty == 0) {
        V(mutex);
    } else {
        empty--;
        V(mutex);
        V(full);
        P(signal);
        被消费
    }
}

翻译成理发店问题就是

semaphore customer = 0; // 等待的顾客数
semaphore mutex = 1; // 保护等待椅
semaphore barber = 0; // 理发师是否可用
int chair = N; // 空椅数

process barber {
    while (true) {
        P(customer);
        P(mutex);
        chair++;
        V(barber);
        V(mutex);
        理发
    }
}

process producer {
    P(mutex);
    if (chair == 0) {
        V(mutex);
    } else {
        chair--;
        V(mutex);
        V(customer);
        P(barber);
        被理发
    }
}

仓库问题

1个仓库最多可以容纳30件产品(不分产品类型),每次只允许一个产品进出仓库。甲乙两个车间分别生产A、B两种产品并共用上述仓库。如果仓库满了,则不能进行新的生产。有3个需要A产品的客户和3个需要B产品的客户,分别从仓库提取A、B产品。请用P、V操作来实现上述甲、乙车间以及A、B产品的客户之间的同步与互斥关系。给出伪代码描述,并添加尽量详细的注释,说明使用的信号量含义,以及主要代码含义。

一样进行问题的分析

1个仓库(缓冲区)最多可以容纳30件产品(不分产品类型)(缓冲区容量30),每次只允许一个产品进出仓库(操作互斥)。甲乙两个车间(两个生产者)分别生产A、B两种产品(两种产品)并共用上述仓库(使用同一个缓冲区)。如果仓库满了(缓冲区满),则不能进行新的生产(需要等待)。有3个需要A产品的客户(消费者类1)和3个需要B产品的客户(消费者类2),分别从仓库提取A、B产品(消费产品)。

翻译为生产者-消费者模型

1个缓冲区最多可以容纳30件产品(不分产品类型),每次只允许一个产品进出缓冲区。有两个生产者分别生产A、B两种产品并共用一个缓冲区。如果缓冲区满,则不能进行新的生产,需要等待缓冲区存在空位。有3个需要A产品的消费者和3个需要B产品的消费者,分别从缓冲区消费A、B产品。

其中,生产者说明了数量为2,生产两种不同商品,且每个生产者是需要多次进行生产的,消费者也指明了数量为6,3个消费A产品,3个消费B产品。产品种类是本题最大的不同点。