Linux|Linux下生产者与消费者模型

1. 概念
??有一个或多个生产者生产某种类型的数据,并放在缓冲区里(生产者),有一个消费者从缓冲区中取数据,每次取一项(消费者)。系统保证任何时候只有一个主题可以访问缓存区。所以当生产满时,生产者不会再生产数据;当缓冲区为空时,消费者不会从中移走数据。 接下来解释同步和互斥的概念,然后用代码(链表、环形队列)模拟生产者与消费者的关系。
??互斥与同步:假设两个或者更多的进程需要访问一个不可共享的资源,如打印机。在执行过程中,每个进程都给该I/O设备发命令,接收状态信息,收发数据。我们把这类资源叫做临界资源,使用临界资源的那一部分程序叫做程序的临界区。而一次只允许一个程序在临界区,即实现原子性(原子性为对外不可分)访问。而使它门有序的进行访问为同步。
2. 生产者与消费者模型
??生产者与生产者之间为互斥关系,消费者与消费者之间为互斥,生产者与消费者之间为为同步、互斥。关系图为:

Linux|Linux下生产者与消费者模型
文章图片

1) 使用链表模拟
??我们采用链表的头插和头删来模拟生产数据和消费数据这两个过程。大致流程如下:
Linux|Linux下生产者与消费者模型
文章图片

代码如下:

#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)环形队列实现
实现流程如下:

Linux|Linux下生产者与消费者模型
文章图片

代码如下:
#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; }

    推荐阅读