1. 概念
??有一个或多个生产者生产某种类型的数据,并放在缓冲区里(生产者),有一个消费者从缓冲区中取数据,每次取一项(消费者)。系统保证任何时候只有一个主题可以访问缓存区。所以当生产满时,生产者不会再生产数据;当缓冲区为空时,消费者不会从中移走数据。 接下来解释同步和互斥的概念,然后用代码(链表、环形队列)模拟生产者与消费者的关系。
??互斥与同步:假设两个或者更多的进程需要访问一个不可共享的资源,如打印机。在执行过程中,每个进程都给该I/O设备发命令,接收状态信息,收发数据。我们把这类资源叫做临界资源,使用临界资源的那一部分程序叫做程序的临界区。而一次只允许一个程序在临界区,即实现原子性(原子性为对外不可分)访问。而使它门有序的进行访问为同步。
2. 生产者与消费者模型
??生产者与生产者之间为互斥关系,消费者与消费者之间为互斥,生产者与消费者之间为为同步、互斥。关系图为:
文章图片
1) 使用链表模拟
??我们采用链表的头插和头删来模拟生产数据和消费数据这两个过程。大致流程如下:
文章图片
代码如下:
#include .h>
#include
#include .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 = https://www.it610.com/article/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;
}
}voidpopFront(pList* pplist, int *data)
{
pList cur = *pplist;
if(cur == NULL)
{
exit(1);
}
while(cur->_next == NULL)
{
*data = https://www.it610.com/article/cur->_data;
free(cur);
cur == NULL;
exit(2);
}
*pplist = cur->_next;
*data = https://www.it610.com/article/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 = https://www.it610.com/article/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 = https://www.it610.com/article/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
#include 【Linux|Linux下生产者与消费者模型】#include
#include
#define SIZE 4int stor[SIZE];
//创建信号量
sem_t blankSem;
sem_t dataSem;
void* consumer()
{
int step = 0;
int data = https://www.it610.com/article/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 = https://www.it610.com/article/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;
}
推荐阅读
- Linux|【Linux】生产者消费者模型
- Linux|【Linux】—— 基于信号量的生产者消费者模型
- Linux|Linux生产者消费者模型
- 程序员宝贵经验集|代码调不通,OJ题不会做(寻求帮助,学会提问-《提问的智慧》)
- 操作系统|实验一 Linux基本操作
- Linux|Linux基本操作
- 校招|校招 --阶段一 系统编程】基于进程控制的实现简单的shell
- Linux|Shell运行原理和Linux权限