操作系统经典同步问题——生产者-消费者问题

问题描述

一组生产者进程和一组消费者进程共享一个初始为空、大小为n的缓冲区,只有缓冲区没满时,生产者才把消息放入缓冲区,否则必须等待;只有缓冲区没空时,消费者从中取出消息,否则必须等待。由于缓冲区是临界资源,它只允许一个生产者放入消息,或一个消费者从中取出消息。

对于同步互斥的解释

首先,在操作系统中的异步指的是进程以不可预知的速度前进,举个例子来说,我想打LOL,需要我先打开客户端登陆,才能打LOL,因此打LOL这个动作要发生在客户端登陆之后,这就是所谓同步(用于进程间的相互制约)。

问题分析

  1. 关系分析
    首先,临界区的意思是一次只能由一个进程访问。而如果一次有两个消费者进程要去访问临界区,那么可能会出现一个进程获得了一些资源,另一个进程获得了另一半资源,造成资源的分配不全,生产者进程也是会造成这样的问题。因此生产者和消费者对于临界区的访问是互斥关系
    其次,消费者只有在生产者生产之后才能消费,而生产者也需要在消费者消费后(使资源不满)才能再生产。这种先后的顺序则是同步关系
  2. 信号量设置
    在此问题中,互斥关系有一对,而同步关系有两对。
    mutex为互斥信号量,初值为1,用于控制互斥访问。
    full为同步信号量,初值为0,记录当前缓冲区中满的缓冲区数
    empty为同步信号量,初值为n,记录当前缓冲区中空的缓冲区数
semaphore mutex=1;
semaphore empty=N;//N表示当前总共有几个缓冲区,empty=N即当前缓冲区均为空
semaphore  full=0;

Consumer(){
	while(1){
		P(full);//需要有满的存有数据的缓冲区
		P(mutex);
		visit()//访问临界区,并消费
		V(mutex);
		V(empty);//提供一个空的缓冲区可供生产
	}
}

Producer(){
	while(1){
		P(empty);//需要空的缓冲区来生产
		P(mutex);
		visit()//访问临界区,并生产
		V(mutex);
		V(full);//提供一个满的缓冲区可供消费
	}
}

注意

对于mutex的PV操作一定要和临界区代码"夹紧",考虑这样一种情况:
当缓冲区已满,empty=0,full=n时

当前面生产者代码中P(empty);P(mutex);互换顺序,先对mutex进行P操作,再对full执行P操作,转换成人话就是在说:我先进入了临界区,但我就是不出去,与此同时我又申请了空闲的缓冲区,因为缓冲区均满,所以P(empty)会锁住,等待消费者代码那的V(empty)来唤醒自己,但是问题就出在这里。

消费者那里的V(empty)在代码的末尾,执行消费者进程时,我还需执行P(mutex)但人生产者还在临界区没出来,你怎么能进的去?所以这里也锁住,等待生产者那边的V(mutex)来唤醒自己。

相信大家也看出来了,这不是我等你你等我谁也等不到嘛?所以这样的交换是有问题的,不能够交换这两句代码的顺序。

你可能感兴趣的:(操作系统,开发语言,系统架构)