须互斥使用,所以另外还需设置一个互斥信号灯mutex,起初值为1。
假定在生产者和消费者之间的公用缓冲区中,具有n个缓冲区,这时可以利用互斥信号量mutex实现诸进程对缓冲池的互斥使用;利用信号量empty和full分别表示缓冲池中空缓冲区和满缓冲区的数量。又假定这些生产者和消费者互相等效果,只要缓冲池未满,生产者便可以将消息送入缓冲池;只要缓冲池未空,消费者便可以从缓冲池中取走一个消息。
在生产者---消费者问题中应注意:首先,在每个程序中用于互斥的wait(mutex)和signal(mutex)必须成对出现;其次,对资源信号量empty和full的wait和signal操作,同样需要成对地出现,但它们分别处于不同的程序中。
生产者与消费者进程共享一个大小固定的缓冲区。其中,一个或多个生产者生产数据,并将生产的数据存入缓冲区,并有一个或多个消费者从缓冲区中取数据。
假设缓冲区的大小为n(存储单元的个数),它可以被生产者和消费者循环使用。分别设置两个指针in和out,指向生产者将存放数据的存储单元和消费者将取出数据的存储单元,如图,指针in和out初始化指向缓冲区的第一个存储单元。生产者从第一个存储单元开始存放数据,一次存放一条数据一条数据且in指针向后移一个位置,当in 指针指向第n个存储单元,下一次将指向第一个存储单元,如此循环反复使用缓冲区。消费者从缓冲区中逐条取走数据,一次取一条数据,相应的存储单元变为“空”,可以被生产者再次使用。每次取走一条数据,out指针向后移一个存储单元位置。试想,如果不控制生产者与消费者,将会产生什么结果?
1 2 3 4 5 6 7 8 n …… ……
In out
1 2 3 4 5 6 7 8 n ……
……
In out
其中,in表示存数据位置,out表示取数据位置
: :被占用单元 :空存储单元 图:生产者/消费者循环使用缓冲区
首先,生产者和消费者可能同时进入缓冲区,甚至可能同时读/写一个存储单元,将导致执行结果不确定。这显然是不允许的。所以,必须使生产者和消费者互斥进入缓冲区。即某时刻只允许一个实体(生产者或消费者)访问缓冲区,生产者互斥消费者和其他任何生产者。
其次,生产者不能向满的缓冲区写数据,消费者也不能在空缓冲区中取数据,即生产者与消费者必须同步。当生产者产生出数据,需要将其存入缓冲区之前,首先检查缓冲区中是否有“空”存储单元,若缓冲区存储单元全部用完,则生产者必须阻塞等待,直到消费者取走一个存储单元的数据,唤醒它。若缓冲区内有“空”存储单元,生产者需要判断此时是否有别的生产者或消费者正在使用缓冲区,若是有,则阻塞等待,否则,获得缓冲区的使用权,将数据存入缓冲区,释放缓冲区的使用权。消费者取数据之前,首先检查缓冲区中是否存在装有数据的存储单元,若缓冲区为“空”,则阻塞等待,否则,判断缓冲区是否正在被使用,若正被使用,若正被使用,则阻塞等待,否则,获得缓冲区的使用权,进入缓冲区取数据,释放缓冲区的使用权。其执行流程如图所示,伪代码如图所示。
2、涉及的数据结构
①用资源向量Available。这是一个含有m个元素的数组,其中的每一个元素代表一类可利用的资源数目,其初始值是系统中所配置的该类全部可用资源的数目,其数值随该类资源的分配和回收而动态地改变。如果Available[j]=K,则表示系统中县有RJ类资源K个。
②需求矩阵MAX。这是一个N*M的矩阵,它定义了系统中N个进程中的每一个进程对M类资源的最大需求。如果MAX[i,j]=K,则表示进程I需要RJ类资源的最大数目为K。
③矩阵Allocation。这也是一个N*M的矩阵,它定义了系统中每一类资源
当前已分配给每一进程的资源数。如果Allocation[i,j]=K,则表示进程i当前已分得RJ类资源的数目为K。
④矩阵Need。这也是一个N*M的矩阵,用以表示每一个进程尚需的各类资源数。如果Need[i,j]=K,则表示进程I还需要RJ类资源K个,方能完成其任务。
上述三个矩阵间存在下述关系: Need[i,j]=MAX[i,j]-Allocation[i,j]
三、数据流程图: 3.1、生产者
3.2、消费者