生产者消费者模型
生产者消费者模型是经典的线程控制与任务传递案例
- 生产者工作条件:仓库非满,添加任务.如果添加任务成功则成功唤醒一个消费者
- 挂起条件:仓库为满,等待唤醒.
- 消费者工作条件:仓库非空,获取任务.获取任务成功则唤醒一个生产者
- 挂起条件:仓库为空,等待唤醒
生产者消费者模型设计分析:
- 任务类别 :消息包,协议包,模块功能
- 任务容器类别 :自定义数据结构(环形队列)
- 确定线程身份:生产者消费者
- 确认生产者消费者的工作条件与挂起条件
使用Mutex、Cond、Pthread实现生产者消费者模型,并进行测试:
- 1生成者线程,10消费者线程
- 任务为功能模块,任务运行时间为2s
- 生产者投递5次任务即可
- 消费者线程持续获取任务(while循环)
代码
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
pthread_mutex_t lock;
pthread_cond_t not_full;
pthread_cond_t not_empty;
typedef struct
{
void *(*tjobs)(void*);
void * arg;
}task_t;
typedef struct
{
int front;
int rear;
int max;
int cur;
task_t * task_queue;
}queue_t;
int pthread_add_task(queue_t *,task_t);
queue_t *pthreadd_container_create(int);
int pthread_containner_destroy(queue_t *);
queue_t *pthread_container_create(int max)
{
queue_t *p;
if((p = (queue_t *)malloc(sizeof(queue_t)))==NULL){
perror("malloc queue call failed");
exit(0);
}
p->front = 0;
p->rear = 0;
p->max = max;
p->cur = 0;
if((p->task_queue = (task_t *)malloc(sizeof(task_t) * max)) == NULL)
{
perror("malloc task_queue call failed");
exit(0);
}
if(pthread_mutex_init(&lock,NULL) != 0 || pthread_cond_init(¬_full,NULL)!=0 || pthread_cond_init(¬_empty,NULL) != 0){
printf("init lock or connd error\n");
exit(0);
}
return p;
}
int pthread_container_destory(queue_t *p)
{
free(p->task_queue);
pthread_mutex_destroy(&lock);
pthread_cond_destroy(¬_full);
pthread_cond_destroy(¬_empty);
free(p);
return 0;
}
int pthread_add_task(queue_t *p,task_t task)
{
pthread_mutex_lock(&lock);
while(p->max == p->cur)
pthread_cond_wait(¬_full,&lock);
p->task_queue[p->front].tjobs = task.tjobs;
p->task_queue[p->front].arg = task.arg;
++(p->cur);
p->front = (p->front +1)%p->max;
pthread_mutex_unlock(&lock);
pthread_cond_signal(¬_empty);
return 0;
}
void * pthread_customer_job(void * arg)
{
task_t task;
queue_t *p = (queue_t *)arg;
while(1){
pthread_mutex_lock(&lock);
while(p->cur ==0)
pthread_cond_wait(¬_empty,&lock);
task.tjobs = p->task_queue[p->rear].tjobs;
task.arg = p->task_queue[p->rear].arg;
--(p->cur);
p->rear = (p->rear+1)% p->max;
pthread_mutex_unlock(&lock);
pthread_cond_signal(¬_full);
task.tjobs(task.arg);
}
pthread_exit(NULL);
}
void * userjobs(void * arg)
{
printf("customer thread tid %x running \n",(unsigned int)pthread_self());
printf("................................\n");
sleep(2);
return NULL;
}
int main()
{
queue_t *p = pthread_container_create(100);
pthread_t tids[10];
for(int i=0;i<10;i++)
pthread_create(&tids[i],NULL,pthread_customer_job,(void*)p);
task_t task;
task.tjobs = userjobs;
task.arg = NULL;
for(int i=0;i<5;i++)
pthread_add_task(p,task);
while(1)
sleep(1);
return 0;
}