互斥锁和条件变量(2)——生产者和消费者(发送消息,循环队列执行)



利用互斥锁和条件变量结合,实现生产者和消费者模型。其中生产者给消费者发送消息,发送字母字符串("a","b","c",...),消费者负责接收。


消息队列为循环队列。

队列为空时,消费者线程挂起,等待激活,等待消息。生产者可以发消息。

队列满时,生产者线程挂起,等待激活,等待消费者处理消息后,激活生产者。



#include <stdio.h>
#include <pthread.h>
#include <time.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>

#define MaxProcMsgNum (10)
#define MaxMsgLen (2)

typedef unsigned long U32;

typedef struct stu_msg_s
{
	pthread_mutex_t share_mutex;
	pthread_cond_t produce_cond;
	pthread_cond_t customer_cond;
	U32 produce_num;
	U32 customer_num;
	U32 max_num;
	U32 conut_current_num;
	U32 msg[MaxProcMsgNum][MaxMsgLen];

}stu_msg_t;

#define InvalidID (U32)(-1)


U32 gs_u32MsgId = InvalidID; //该id为保存内存通信地址使用

static void * customer_proc_func(void * pArg); 

static  int  customer_msg_recv(U32 * pMsgId,U32 * pArrMsg);


static int  produce_msg_send(U32 * pMsgId,U32 * pArrMsg);

static void * produce_proc_func(void * pArg);


static void create_id(U32 * pMsgId);

static void destroy_id(const  U32 pMsgId);

int main()
{
    int i = 0;
	gs_u32MsgId = InvalidID;
	
    create_id( &gs_u32MsgId );
	if(InvalidID == gs_u32MsgId )
	{
		printf("\n if(InvalidID == gs_u32MsgId )  main\n");
		return -1;
	}

	//创建消费者线程
	{
		pthread_t customer_pth_id = -1;
		int ret = -1;
		pthread_attr_t  * customer_attr = NULL;
		void *customer_arg = NULL;
		ret = pthread_create(&customer_pth_id,customer_attr,customer_proc_func,customer_arg);
		usleep(1000);
	}

	//创建生产线程
	{
		pthread_t produce_pth_id = -1;
		int ret = -1;
		pthread_attr_t  * produce_attr = NULL;
		void *produce_arg = NULL;
		ret = pthread_create(&produce_pth_id,produce_attr,produce_proc_func,produce_arg);
		usleep(1000);
	}

	sleep(4);
	
    if(InvalidID != gs_u32MsgId)
	{	
		destroy_id(gs_u32MsgId);
	}
	
	return 0;
}


static void * customer_proc_func(void * pArg)
{
	int ret = -1;
	U32 Arr[MaxMsgLen] = {0}; 
	while(1)
	{
    //监控是否有生产出新东西,赶紧消费了
		memset(Arr, 0 ,sizeof(Arr));
		ret = customer_msg_recv(&gs_u32MsgId , Arr);
		if(0 == ret)
		{
			if(Arr[0] != 0)
			{
				printf(" customer_proc_func   recv ==== [str=%s,len= %lu] \n",(char*)(Arr[0]),Arr[1]);
				free((char*)(Arr[0]));
			}
		}

		usleep(100);
	}
} 


static void * produce_proc_func(void * pArg)
{
	int ret = -1;
	int i = -1;
	char string[] = "a";
	while(1)
	{
        for (i = 0; i < 15 ; i++)
		{
			char *str = NULL;
			int stringlen = 20;
			U32 u32Arr[MaxMsgLen] = {0};
			str = (char *)malloc(stringlen);
			if(NULL == str)
			{
				break;
			}
			
			memset(str, 0, stringlen);
			strncpy(str, string,stringlen-1);
			u32Arr[0] = (U32)str;
			u32Arr[1] = stringlen;
			printf("send i =  %d  str[%s] produce_proc_func\n",i,str);
			
			produce_msg_send(&gs_u32MsgId,u32Arr);
			string[0] += 1;
			usleep(100);
			
		}
		//sleep(5);
		break;
	}
} 

static void create_id(U32 * pMsgId)
{
    stu_msg_t * pMsg= NULL;
	int ret =0 ;

	if(NULL == pMsgId)
	{
		printf("\n if(NULL == pMsgId) create_id\n");
		return ;
	}

	pMsg = (stu_msg_t *)malloc( sizeof(stu_msg_t) );

	if(NULL == pMsg)
	{
		printf("\n if(NULL == pMsg) create_id\n");
		return ;
	}

	*pMsgId = (U32)pMsg;

	memset(pMsg,0,sizeof(stu_msg_t));

	printf("\npMsg = %p\n",pMsg);
 	ret = pthread_mutex_init(&(pMsg->share_mutex), NULL );
    printf("  ret = pthread_mutex_init  %d\n",ret);

	ret = pthread_cond_init(&(pMsg->customer_cond), NULL); 
	printf("  ret = pthread_cond_init  %d\n",ret);

	ret = pthread_cond_init(&(pMsg->produce_cond), NULL); 
	printf("  ret = pthread_cond_init  %d\n",ret);

	pMsg->max_num = MaxProcMsgNum;

	pMsg->customer_num = 0;

	pMsg->produce_num = 0;
	pMsg->conut_current_num = 0;

	printf("\n  create_id  ----finish \n");
	
	return;
	
}

static void destroy_id(const  U32 MsgId)
{
	stu_msg_t * pMsg = NULL;
	int ret1 = 0;
	int ret2 = 0;
	int ret3 = 0;
	pMsg =  (stu_msg_t *)MsgId;

	//printf("\n  destroy_id  pMsg = %p\n",pMsg);
	if(NULL == pMsg || InvalidID == MsgId )
	{
		printf("\n 	if(InvalidID == pMsgId || NULL == pMsg)  destroy_id \n");
		return;
	}
	//pthread_cond_broadcast;
    //先唤醒所有的线程
	pthread_cond_broadcast(&(pMsg->customer_cond));

	ret1 = pthread_cond_destroy(&(pMsg->customer_cond));
	
	pthread_cond_broadcast(&(pMsg->produce_cond));
	
	ret2 = pthread_cond_destroy(&(pMsg->produce_cond));

	ret3 = pthread_mutex_destroy(  &(pMsg->share_mutex) );
	
	free(pMsg);

	printf("\n  destroy_id  ----finish  ret1[%d]  ret2[%d],ret3[%d]\n",ret1,ret2,ret3);
	
	return ;
}

//相当于出队
static  int  customer_msg_recv(U32 * pMsgId,U32 * pArrMsg)
{
	stu_msg_t * pMsg = NULL;
	int ret = -1;
	pMsg =  (stu_msg_t *)(*pMsgId);
	int isfull =0;

	//printf("\n  aaaaaa  pMsg = %p\n",pMsg);
	if( NULL == pMsg || InvalidID == *pMsgId || NULL == pArrMsg)
	{
		return -1;
	}
	
	ret = pthread_mutex_lock(&(pMsg->share_mutex));
	if(0 != ret)
	{
		return -1;
	}

	if(pMsg->customer_num == pMsg->produce_num ) //处理
	//队列为空
	{
		 printf("\n ***pthread_cond_wait-----customer_cond***\n");
		 ret = pthread_cond_wait(&(pMsg->customer_cond),&(pMsg->share_mutex)); //等待唤醒
	}
	if(pMsg->conut_current_num == 0) //销毁时的唤醒
	{
		ret = pthread_mutex_unlock(&(pMsg->share_mutex));
		return 0;
	}
    memset(pArrMsg, 0 ,sizeof(pMsg->msg[0]));
	memcpy(pArrMsg,pMsg->msg[pMsg->customer_num] , sizeof(pMsg->msg[0]));
	
	pMsg->customer_num++;//处理了一个
	if(pMsg->customer_num == pMsg->max_num)
	{
		pMsg->customer_num = 0;
	}
	pMsg->conut_current_num--;

	//判断队列是否是满的
	//不是满的,可以允许入队了啊

	isfull = ( (pMsg->produce_num+1)%pMsg->max_num)==(pMsg->customer_num);


	if( !isfull) //isfull 0  队列未满啊
	{	
	   pthread_cond_signal(&(pMsg->produce_cond));//激活挂起的生产线程
		
	}
	ret = pthread_mutex_unlock(&(pMsg->share_mutex));

	return 0;
}

//考虑循环消息队列
//发消息相当于把消息加入队列,接收到消息并处理
//相当于出队
static int  produce_msg_send(U32 * pMsgId, U32 * pArrMsg)
{

	stu_msg_t * pMsg = NULL;
	int ret = -1;
	pMsg =  (stu_msg_t *)(*pMsgId);
	int isfull = 0;

	if(NULL == pMsg || InvalidID == *pMsgId || NULL == pArrMsg)
	{
		return -1;
	}
	//队列是否满了
	//满了就条件等待,就等待激活,挂起
	ret = pthread_mutex_lock(&(pMsg->share_mutex));
	if(0 != ret)
	{
		return -1;
	}

	isfull = ( (pMsg->produce_num+1)%pMsg->max_num)==(pMsg->customer_num);

	if( isfull) //生产太多东西了,消费者那边消费不过来
	//所以,暂时停产一下
	//队列已满
	{
		 ret = pthread_cond_wait(&(pMsg->produce_cond),&(pMsg->share_mutex)); //等待唤醒
	}
	
	memset(pMsg->msg[pMsg->produce_num],0,sizeof(pMsg->msg[pMsg->produce_num]));
	memcpy(pMsg->msg[pMsg->produce_num],pArrMsg,sizeof(pMsg->msg[pMsg->produce_num]));//pArrMsg

	pMsg->produce_num++;
	if(pMsg->produce_num == pMsg->max_num)
	{
		pMsg->produce_num = 0;
	}
	pMsg->conut_current_num++;

    //通知消费者消费
	pthread_cond_signal(&(pMsg->customer_cond));//激活挂起的消费进程
	
	ret = pthread_mutex_unlock(&(pMsg->share_mutex));

	return 0;
}




执行结果:


root@ubuntu:/share# 
root@ubuntu:/share# gcc test.c -lpthread
root@ubuntu:/share# 
root@ubuntu:/share# ./a.out             

pMsg = 0x979b008
  ret = pthread_mutex_init  0
  ret = pthread_cond_init  0
  ret = pthread_cond_init  0

  create_id  ----finish 


 ***pthread_cond_wait-----customer_cond***
send i =  0  str[a] produce_proc_func
 customer_proc_func   recv ==== [str=a,len= 20] 

 ***pthread_cond_wait-----customer_cond***
send i =  1  str[b] produce_proc_func
 customer_proc_func   recv ==== [str=b,len= 20] 

 ***pthread_cond_wait-----customer_cond***
send i =  2  str[c] produce_proc_func
 customer_proc_func   recv ==== [str=c,len= 20] 

 ***pthread_cond_wait-----customer_cond***
send i =  3  str[d] produce_proc_func
 customer_proc_func   recv ==== [str=d,len= 20] 

 ***pthread_cond_wait-----customer_cond***
send i =  4  str[e] produce_proc_func
 customer_proc_func   recv ==== [str=e,len= 20] 

 ***pthread_cond_wait-----customer_cond***
send i =  5  str[f] produce_proc_func
 customer_proc_func   recv ==== [str=f,len= 20] 

 ***pthread_cond_wait-----customer_cond***
send i =  6  str[g] produce_proc_func
 customer_proc_func   recv ==== [str=g,len= 20] 

 ***pthread_cond_wait-----customer_cond***
send i =  7  str[h] produce_proc_func
 customer_proc_func   recv ==== [str=h,len= 20] 

 ***pthread_cond_wait-----customer_cond***
send i =  8  str[i] produce_proc_func
 customer_proc_func   recv ==== [str=i,len= 20] 

 ***pthread_cond_wait-----customer_cond***
send i =  9  str[j] produce_proc_func
 customer_proc_func   recv ==== [str=j,len= 20] 

 ***pthread_cond_wait-----customer_cond***
send i =  10  str[k] produce_proc_func
 customer_proc_func   recv ==== [str=k,len= 20] 

 ***pthread_cond_wait-----customer_cond***
send i =  11  str[l] produce_proc_func
 customer_proc_func   recv ==== [str=l,len= 20] 

 ***pthread_cond_wait-----customer_cond***
send i =  12  str[m] produce_proc_func
 customer_proc_func   recv ==== [str=m,len= 20] 

 ***pthread_cond_wait-----customer_cond***
send i =  13  str[n] produce_proc_func
 customer_proc_func   recv ==== [str=n,len= 20] 

 ***pthread_cond_wait-----customer_cond***
send i =  14  str[o] produce_proc_func
 customer_proc_func   recv ==== [str=o,len= 20] 

 ***pthread_cond_wait-----customer_cond***

  destroy_id  ----finish  ret1[0]  ret2[0],ret3[0]
root@ubuntu:/share# 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值