首页 > 程序开发 > 软件开发 > 其他 >

生产者消费者模型(一)

2017-07-04

生产者消费者模型(一),什么是生产者和消费者模型?在实际的软件开发中,经常会遇到这样的场景:某个模块负责生产数据,这些数据由另一个模块来负责处理。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。

生产者消费者模型(一)

什么是生产者和消费者模型?

在实际的软件开发中,经常会遇到这样的场景:某个模块负责生产数据,这些数据由另一个模块来负责处理。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。

对于生产者/消费者模型来说,上面所述还需一个缓冲区,这个缓冲区处于生产者和消费者之间,作为一个中介。
生产者将数据放入缓冲区,而消费者从缓冲区取出数据。

这里写图片描述

生产者和消费者模型为什么需要缓冲区?

1.解耦

假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化,可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。

2.支持并发

生产者直接调用消费者的某个方法,还有另一个弊端。由于函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回之前,生产者只好一直等在那边。万一消费者处理数据很慢,生产者就会白白糟蹋大好时光。
使用了生产者/消费者模式之后,生产者和消费者可以是两个独立的并发主体。生产者把制造出来的数据往缓冲区一丢,就可以再去生产下一个数据。基本上不用依赖消费者的处理速度。

3.支持忙闲不均

缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。


生产者与消费者模型

遵循“321原则(只是为了好记忆而已,没有其他的特殊含义)”

三种关系:

生产者与生产者:互斥的关系
(例如生产同一商品的厂家之间的相互竞争)

消费者与消费者:互斥的关系
(消费者和消费者之间并没有同步的关系,例如,我们去超市买东西,不可能不允许其他人也去超市买东西,而且在资源充足的情况下,消费者和消费者之间并没有什么很明显的关系,只有在资源特别匮乏的时候,消费者与消费者之间才会形成竞争关系)。

生产者与消费者:同步与互斥的关系
(首先来说互斥关系,当生产者正在生产的时候,消费者不可能去拿数据,否则可能会导致数据的不一致问题,再来看看同步关系,生产者和消费者必须是同步的,否则会引发这样的问题,当生产者还没有生产的 时候,消费者一直占用锁资源,但是并没有资源可供消费者消费,但是由于消费者一直占用锁资源,可能会导致生产者的饥饿问题)。

两种角色:

生产者和消费者:在Linux下,一般是进程或者线程来充当这样的角色。

一个交易场所:(在使用单链表来实现的时候,这条单链表充当的就是这个交易场所)。

一般是内存中可以存储数据的一个缓冲区。(可以是结构体、数组、链表等数据结构)。
生产者向这个缓冲区中放数据,而消费者向这个交易场所拿数据。

生产者和消费者遵循下面的规则:

1.当生产者向这个缓冲区中放数据时,消费者想消费时,这时应该将消费者挂起等待。

2.如果消费者正从这个缓冲区中拿数据时,这时如果生产者还想向这个缓冲区放数据,那么就应该将生产者挂起等待。

上面两个规则本质上就是在遵循互斥原则。
当生产者生产满时就应该释放锁资源,使得消费者可以获得锁资源,从而可以从缓冲区中拿数据。
这个就是所谓的同步机制。


实现基于单链表的生产者和消费者模型:

这里写图片描述

结果如下:
每生产一次,消费者就消费一次。

这里写图片描述

与条件变量相关的函数:

1.条件变量的初始化:

这里写图片描述

条件变量:数据类型为pthread-cond_t
静态的条件变量可以使用宏来初始化,局部的条件变量需要使用函数pthread_cond_init来进行初始化。

2.唤醒线程:

这里写图片描述

pthread-cond_signal函数唤醒一个等待某个条件变量的线程,参数为条件变量(是一个输出型参数)。—》唤醒的这个线程可以直接获得锁。

pthread_cond-broadcast函数唤醒等待某个条件变量的所有线程。(但是唤醒所有线程可能会导致进程不稳定)。

3.线程等待资源:

这里写图片描述

从该函数可以看出:条件变量总是和一个Mutex相互配合使用。
一个线程可以调用pthread_cond_wait等待条件变量,该函数一般会做下面三个操作:
1.释放锁资源(Mutex)
2.阻塞等待(休眠状态)
3.当被唤醒时,获得锁资源并返回。(返回到之前等待时的下一条指令处,执行下面的操作)。
(这里获得的锁资源依然是之前等待时释放的锁资源)。

相关文章
最新文章
热点推荐