C语言之生产者与消费者模型

多线程并发应用程序有一个经典的模型,即生产者/消费者模型。系统中,产生消息的是生产者,处理消息的是消费者,消费者和生产者通过一个缓冲区进行消息传递。生产者产生消息后提交到缓冲区,然后通知消费者可以从中取出消息进行处理。消费者处理完信息后,通知生产者可以继续提供消息。

要实现这个模型,关键在于消费者和生产者这两个线程进行同步。也就是说:只有缓冲区中有消息时,消费者才能够提取消息;只有消息已被处理,生产者才能产生消息提交到缓冲区。

   我们用一个队列来做这个缓冲区,产生的消息我们放到这个队列中去,如果这个队列满了,则不放入消息,我们这个队列大小是10,能够存放10条消息。然后消费者去消费,消费者去这个缓冲区里去取数据,同样,如果缓冲区里没有数据,那么就不会消费。

  这一模型的核心就是消费者和生产者一起去抢互斥锁,谁抢到了这个锁谁就有资格对这个缓冲区进行相关操作。


代码:
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
#include <time.h>

#define TRUE  1
#define FALSE 0
#define SIZE 11

typedef int QueueData;
typedef struct _queue   //队列结构体
{
	int data[SIZE];
	int front;     // 指向队头的下标
	int rear;      // 指向队尾的下标
}Queue;

struct data             //信号量结构体
{
	sem_t empty;
	sem_t full;
	Queue q;
};

pthread_mutex_t mutex;

int num = 0;

struct data sem;

int InitQueue (Queue *q)   // 队列初始化
{
	if (q == NULL)
	{
		return FALSE;
	}
	
	q->front = 0;
	q->rear  = 0;
	
	return TRUE;
}

int QueueEmpty (Queue *q)      //判断空对情况
{
	if (q == NULL)
	{
		return FALSE;
	}
	
	return q->front == q->rear;
}

int QueueFull (Queue *q)     //判断队满的情况
{
	if (q == NULL)
	{
		return FALSE;
	}
	
	
	return q->front == (q->rear+1)%SIZE;
} 

int DeQueue (Queue *q, int *x)   //出队函数
{
	if (q == NULL)
	{
		return FALSE;
	}
	
	if (QueueEmpty(q))
	{
		return FALSE;
	}
	q->front = (q->front + 1) % SIZE;
	*x = q->data[q->front];
	
	return TRUE;
}

int EnQueue (Queue *q, int x)   //进队函数
{
	if (q == NULL)
	{
		return FALSE;
	}
	
	if (QueueFull(q))
	{
		return FALSE;
	}
	
	q->rear = (q->rear+1) % SIZE;
	q->data[q->rear] = x;
	
	return TRUE;
}

void *Producer()
{
	while(1)
	{
		int time = rand() % 10 + 1;          //随机使程序睡眠0点几秒
		usleep(time * 100000);                 
		                                      
		sem_wait(&sem.empty);                 //信号量的P操作
		pthread_mutex_lock(&mutex);           //互斥锁上锁
		                                      
		num++;                                
		EnQueue (&(sem.q), num);              //消息进队
		printf("生产了一条消息:%d\n", num);  
		                                      
		pthread_mutex_unlock(&mutex);         //互斥锁解锁
		sem_post(&sem.full);                  //信号量的V操作
	}
}

void *Consumer()
{
	while(1)
	{
		int time = rand() % 10 + 1;   //随机使程序睡眠0点几秒
		usleep(time * 100000);
		
		sem_wait(&sem.full);           //信号量的P操作
		pthread_mutex_lock(&mutex);    //互斥锁上锁
		
		num--;
		DeQueue (&sem.q, &num);       //消息出队
		printf("消费了一条消息\n");
		
		pthread_mutex_unlock(&mutex);  //互斥锁解锁
		sem_post(&sem.empty);         //信号量的V操作
	}
}

int main()
{
	srand((unsigned int)time(NULL));
	
	sem_init(&sem.empty, 0, 10);    //信号量初始化(做多容纳10条消息,容纳了10条生产者将不会生产消息)
	sem_init(&sem.full, 0, 0);
	
	pthread_mutex_init(&mutex, NULL);  //互斥锁初始化
	
	InitQueue(&(sem.q));   //队列初始化
	
	pthread_t producid;
	pthread_t consumid;
	
	pthread_create(&producid, NULL, Producer, NULL);   //创建生产者线程
	pthread_create(&consumid, NULL, Consumer, NULL);   //创建消费者线程
	
	pthread_join(consumid, NULL);    //线程等待,如果没有这一步,主程序会直接结束,导致线程也直接退出。
	
	sem_destroy(&sem.empty);         //信号量的销毁
	sem_destroy(&sem.full);    
	
	pthread_mutex_destroy(&mutex);   //互斥锁的销毁
	
	return 0;
}

效果图:



  • 11
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值