题20

题目

【2014 统考真题】系统中有多个生产者进程和多个消费者进程, 共享一个能存放 1000 件产品的环形缓冲区 (初始为空)。
缓冲区未满时, 生产者进程可以放入其生产的一件产品, 否则等待;
缓冲区未空时, 消费者进程可从缓冲区取走一件产品, 否则等待。
要求一个消费者进程从缓冲区连续取出 10 件产品后, 其他消费者进程才可以取产品。
请使用信号量P, V (wait (),signal())操作实现进程间的互斥与同步, 要求写出完整的过程, 并说明所用信号量的含义和初值。

分析

题20

我感觉还是只用维护一个empty和full,只是需要给解mutex锁额外补一个条件,就是一个消费者进程从缓冲区连续取出 10 件产品后, 其他消费者进程才可以取产品,其他的和生产者-消费者问题,我认为没有什么区别
注意:这里这个解锁条件,是在消费者内部的,因为有多个消费者,必须在消费者内部定义这个计数器,把它维护成消费者中的mutex,应该是不可以硬编码实现的
上面的逻辑有问题,为了防止多个消费者之间竞争,应该在消费者内部维护一把锁mutex,保证每次都只有一个人在读缓冲区,count可以不用变量维护,直接硬编码

semaphore mutex = 1, empty = 1000, full = 0, count = 10, othe_mutex=1; //这个计数器其实也可以不用变量维护,直接硬编码,应该也可以
// 生产者进程
void producer( i ) {
	while(1) {
		//生产产品
		P(empty); //获取空位
		//如果有空位,解锁开始生产
		P(mutex); //锁住缓冲区
		//放入产品
		V(mutex); //解锁缓冲区
		V(full); //释放产品
	}
}
 
void error_comsumer(i) {
	 while(1) {
		 //先防止其他进程读缓冲区
		 P(othe_mutex);
		 //检查有没有东西能消费
		 P(full);
		 //如果有东西可以消费,就开始消费
		 P(mutex);
		 //连续读10次,才能让其他人读
		 for(int i = 0; i < 10; i++) {
       //从缓冲区取出产品
     }
	 }
}
 
//上面这么写是错的,每次读也都要检查full,for循环应该是一个大循环
void consumer(i) {
	while(1) {
		//防止其他进程读缓冲区
		P(othe_mutex);
		//开始读10次
		for(int i = 0; i < 10; i++) {
	      //检查有没有东西能消费
	      P(full);
	      //如果有东西可以消费,就开始消费
	      P(mutex);
	      //从缓冲区取出产品
	      V(mutex);
	      V(empty);
	    }
	}
	//放掉消费者的锁,让其他消费者可以读缓冲区
	V(othe_mutex);
}

题47

这是典型的生产者和消费者问题, 只对典型问题加了一个条件, 只需在标准模型上新加一个信号量, 即可完成指定要求。

设置 4 个变量 mutex1, mutex2, empty 和 full, mutex1 用于控制一个消费者进程在一个周期(10 次) 内对缓冲区的访问,初值为 1 ;
mutex2 用于控制进程单次互斥地访问缓冲区,初值为 1 ;
empty 代表缓冲区的空位数, 初值为 1000 ;
full 代表缓冲区的产品数, 初值为 0 , 具体进程描述如下:

// 用于实现生产者之间的互斥
semaphore mutex1 = 1;
// 用于实现消费者之间的互斥
semaphore mutex2 = 1;
// 空缓冲区数
semaphore empty = 1000;
// 非空缓冲区数
semaphore full = 0;
 
// 生产者进程
producer() {
    while (1) {
        // 生产一个产品
        P(empty);
        P(mutex2);
        // 把产品放入缓冲区
        V(mutex2);
        V(full);
    }
}
 
// 消费者进程
consumer() {
    while (1) {
        P(mutex1); // 连续取 10 次
        for (int i = 0; i < 10; i++) {
            P(full); // 判断缓冲区是否有产品
            P(mutex2); // 互斥访问缓冲区
            // 从缓冲区取出一件产品
            V(mutex2); // 互斥访问缓冲区
            V(empty); // 腾出一个空位
            // 消费这件产品
        }
        V(mutex1);
    }
}