在“进程间通信----信号量”一文中,有简单介绍过生产者消费者模型的基本概念。在下文中将使用有关线程的互斥与同步的相关概念来实现两种不同类型的生产者消费者模型。在本文中侧重于线程间同步的实现。有关线程互斥与同步的相关概念见线程的互斥与同步一文:
首先介绍该模型的背景知识:
生产者消费者问题
该问题是一个著名的同步问题。它描述的是:一群生产者进程正在生产产品,并将这些产品提供给消费者进程去消费。为使生产者和消费者能够并发执行。在两者之间设置了一个公共区域,生产者进入公共区域生产产品并放入其中。消费者进入公共区域并取走产品进行消费。
当一个生产者进入公共区域生产产品时,其他生产者和消费者不能同时进入公共区域生产产品或消费产品。当一个消费者进入公共区域消费产品的时候,其它消费者和生产者不能同时进入该区域消费产品或生产产品。也就是说,任意时刻,最多只允许一个生产者或一个消费者进入公共区域。即生产者和消费者必须互斥的访问公共区域。
当产品放满公共区域时,生产者必须等待,使消费者先消费。当公共区域为空时,消费者必须等待,使生产者先生产。即在公共区域为空或为满时,生产者或消费者在执行时要满足一定的先后顺序。即生产者与消费者对公共区域的访问必须同步。
根据以上描述,可以得出如下结论:
(1)生产者与生产者之间存在竞争即互斥关系
(2)消费者与消费者之间存在竞争即互斥关系
(3)生产者与消费者之间存在互斥与同步关系
以上三个结论可以概括为:三种关系,两种角色,一个临界区。即“三二一”规则。
下面根据具体研究不同类型的生产者消费者模型:
利用链表做临界资源的生产者消费者模型:
在该模型中临界资源为一带头节点的单向链表。多个生产者在向链表中头插节点,多个消费者在对链表进行头删结点。
在一个生产者头插结点或一个消费者在头删结点的过程中,其他生产者或消费者不能对该链表进行操作。因此:生产者与生产者之间,消费者与消费者之间,生产者与消费者之间存在互斥关系。在这里,通过互斥量来保证互斥关系。
因为链表是动态插入结点,所以可以说链表没有满的时候(不考虑内存满的情况)。所以这里只需考虑链表为空的时候。当链表为空时,生产者必须先执行头插结点。此时,便需要生产者与消费者在执行时满足一定的顺序要求。即生产者与消费者必须同步的访问链表。
通过以上分析,生产者与消费者之间满足上述的三个结论。
1. 利用条件变量保证线程间的同步
在该模型中,利用多个线程来模拟生产者与消费者,互斥量来保证生产者消费者任意两者之间的互斥关系,条件变量来保证生产者与消费者之间的同步关系。当链表为空时,使用条件变量使消费者线程挂起等待。有关互斥量与条件变量的使用见本文开头的博客链接。
下面模拟该模型:
定义互斥量和条件变量:
pthread_mutex_t mutex;