利用互斥锁和条件变量结合,实现生产者和消费者模型。其中生产者给消费者发送消息,发送字母字符串("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#