今天我们来写一个基于固定大小的环形队列的生产者消费者模型。
首先来画图说明一下
这是一个环形队列的生产者消费者模型。生产者用P表示,消费者用C表示。这个环形队列的每一段空间我们用semBlank表示,放入的内容我们用semData表示。生产者首先要申请一个semBlank,然后放入semData。消费者则是要先拿一个semData,然后释放一个semBlank。在这个环形队列中我们要考虑几种情况
1、一开始生产者与消费者在同一起跑线,但是我们必须要让生产者先操作,因为只有生产者生产了数据,消费者才可以去拿数据。如果生产者还没有生产数据就让消费者去拿数据,那么就会拿到一些非法数据。所以在运行过程中我们一定要保持生产者在消费者的前面。
2、当生产者已经跑完了一圈,每个semBlank上都有数据,而消费者没有拿数据,这是生产者和消费者再次重合的时候,就要让消费者先操作,因为如果让生产者继续操作的话又一轮生产的数据将会覆盖到之前的数据。即生产者不能将消费者套圈。
所以我们引入了两个信号量去解决这个问题,当生产者要生产数据的时候要先去申请一个semBlank,相当于P操作,申请成功后我们要放入一个数据,就相当于V操作。而对于消费者来说,首先要拿一个数据,相当于P操作,拿到一个数据后要释放一个semBlank,就相当于V操作。我们的semBlank是从n到0的,而semData是从0到n的。
下面我们来介绍POSIX信号量。
POSIX信号量和System V信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。但POSIX可以用于线程间同步。
#include <semaphore.h> //初始化信号量
int sem_init(sem_t *sem,int pshared,unsigned int value)
//参数:
// pshared:0表示线程间共享,非零表示进程间共享
// value:信号量初始值
int sem_destroy(sem_t *sem); //销毁信号量
int sem_wait(sem_t *sem); //等待信号量
//功能:等待信号量,会将信号量的值减1
int sem_post(sem_t *sem) //发布信号量
//功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1.
现在我们来用代码来实现固定大小的环形队列的生产者消费者模型。
#include <unisted.h>
#include <sys/types.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
#define CONSUMERS_COUNT 1
#define PRODUCERS_COUNT 1
#define BUFFSIZE 10
int g_buffer [BUFFSIZE];
unsigned short in = 0;
unsigned short out = 0;
unsigned short produce_id = 0;
unsigned short consume_id = 0;
sem_t g_sem_full;
sem_t g_sem_empty;
pthread_mutex_t g_mutex;
pthread_t g_thread[CONSUMERS_COUNT+PRODUCERS_COUNT];
void* cousume(void *arg)
{
int i;
int num = *(int*)arg;
free(arg);
while(1)
{
printf("%d wait buffer not empty\n",num);
sem_wait(&g_sem_empty);
pthread_mutex_lock(&g_mutex);
for(i=0;i<BUFFSIZE;i++)
{
printf("%2d",i);
if(g_buffer[i] == -1)
printf("%s","null");
else
printf("%d",g_buffer[i]);
if(i == out)
printf("\t<--cos