1. 概念
有一个或多个生产者生产某种类型的数据,并放在缓冲区里(生产者),有一个消费者从缓冲区中取数据,每次取一项(消费者)。系统保证任何时候只有一个主题可以访问缓存区。所以当生产满时,生产者不会再生产数据;当缓冲区为空时,消费者不会从中移走数据。 接下来解释同步和互斥的概念,然后用代码(链表、环形队列)模拟生产者与消费者的关系。
互斥与同步:假设两个或者更多的进程需要访问一个不可共享的资源,如打印机。在执行过程中,每个进程都给该I/O设备发命令,接收状态信息,收发数据。我们把这类资源叫做临界资源,使用临界资源的那一部分程序叫做程序的临界区。而一次只允许一个程序在临界区,即实现原子性(原子性为对外不可分)访问。而使它门有序的进行访问为同步。
2. 生产者与消费者模型
生产者与生产者之间为互斥关系,消费者与消费者之间为互斥,生产者与消费者之间为为同步、互斥。关系图为:
1) 使用链表模拟
我们采用链表的头插和头删来模拟生产数据和消费数据这两个过程。大致流程如下:
代码如下:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
typedef struct List
{
int _data;
struct List* _next;
}List,*pList;
pList getNode(int d)
{
pList node = (pList)malloc(sizeof(List));
if(node == NULL)
{
perror("malloc");
exit(1);
}
node->_data = d;
node->_next = NULL;
return node;
}
void pushFront(int d, pList* pplist)
{
pList node= getNode(d);
if(*pplist == NULL)
*pplist = node;
else
{
node->_next = *pplist;
*pplist = node;
}
}
void popFront(pList* pplist, int *data)
{
pList cur = *pplist;
if(cur == NULL)
{
exit(1);
}
while(cur->_next == NULL)
{
*data = cur->_data;
free(cur);
cur == NULL;
exit(2);
}
*pplist = cur->_next;
*data = cur->_data;
free(cur);
}
int isEmpty(pList l)
{
if(l == NULL)
{
return 1;
}
return 0;
}
void desList(pList* pplist)
{
pList cur = *pplist;
pList del = NULL;
while(cur != NULL)
{
del = cur;
cur = cur->_next;
free(del);
del = NULL;
}
*pplist = NULL;
}
//静态方式创建,赋予常量
pthread_cond_t mycond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
pList list = NULL;
void* consume(void* arg)
{
int data = 0;
while(1)
{
sleep(2);
//阻塞式加锁
pthread_mutex_lock(&mylock);
while(isEmpty(list))
{
//条件不满足时,进入阻塞式等待
pthread_cond_wait(&mycond, &mylock);
}
popFront(&list,&data);
printf("consume get : %d\n",data);
//解锁
pthread_mutex_unlock(&mylock);
}
}
void* product( void* arg)
{
int data = 0;
while(1)
{
pthread_mutex_lock(&mylock);
data = rand()%100;
pushFront(data,&list);
printf("product put : %d\n",data);
pthread_mutex_unlock(&mylock);
//激活一个等待该条件的线程
pthread_cond_signal(&mycond);
sleep(1);
}
}
int main()
{
pthread_t tid1,tid2;
//线程的创建与等待
pthread_create(&tid1, NULL, consume, NULL);
pthread_create(&tid2, NULL, product, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
desList(&list);
pthread_mutex_destroy(&mylock);
//没有线程在该条件变量上等待的时候注销这个条件
//变量,否则返回EBUSY
pthread_cond_destroy(&mycond);
return 0;
}
2)环形队列实现
实现流程如下:
代码如下:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <semaphore.h>
#define SIZE 4
int stor[SIZE];
//创建信号量
sem_t blankSem;
sem_t dataSem;
void* consumer()
{
int step = 0;
int data = 0;
while(1)
{
sleep(1);
//等待数据信号量
sem_wait(&dataSem);
data = stor[step++];
//释放空格信号量
sem_post(&blankSem);
step %= SIZE;
printf("consumer get: %d\n",data);
}
}
void* producter()
{
int step = 0;
int data = 0;
while(1)
{
sem_wait(&blankSem);
stor[step++] = data++;
sem_post(&dataSem);
step %= SIZE;
printf("producter put: %d\n",data);
}
}
int main()
{
//初始化信号量,格子SIZE个,数据0个
sem_init(&blankSem, 0, SIZE);
sem_init(&dataSem, 0, 0);
pthread_t td1,td2;
//创建和等待线程
pthread_create(&td1, NULL, consumer, NULL);
pthread_create(&td2, NULL, producter, NULL);
pthread_join(td1, NULL);
pthread_join(td2, NULL);
//销毁信号量
sem_destroy(&blankSem);
sem_destroy(&dataSem);
return 0;
}