基于上一节生产者消费者问题--进阶再结合顺序循环队列来实现生产者消费者问题
主要变化就是把需要操作的资源变成操作循环队列,代码如下:
circularQueue.h
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #define FREE(p) if (p != NULL) { free(p); p = NULL; } typedef struct{ //int data[QUEUE_SIZE]; //队列中的元素 int *data; int cqHead; //指向队首元素 int cqTail; //指向队尾元素 int size; //当前队列的大小 int maxSize; //可以容纳的最大大小 }CIRCULAR_QUEUE, *P_CIRCULAR_QUEUE; int IsQueEmpty(P_CIRCULAR_QUEUE cQue); int IsQueFull(P_CIRCULAR_QUEUE cQue); int getQueueSize(P_CIRCULAR_QUEUE cQue); int getQueueHead(P_CIRCULAR_QUEUE cQue); int getQueueHeadData(P_CIRCULAR_QUEUE cQue); int getQueueTail(P_CIRCULAR_QUEUE cQue); int getQueueTailData(P_CIRCULAR_QUEUE cQue); //队列是先进先出FIFO void InitCircularQue(P_CIRCULAR_QUEUE cQue, int maxsize); void enterCircularQue(P_CIRCULAR_QUEUE cQue, int elem); int leaveCircularQue(P_CIRCULAR_QUEUE cQue); void ShowQue(P_CIRCULAR_QUEUE cQue); void delQue(P_CIRCULAR_QUEUE cQue);
circularQueue.c
/*初始化:head = tail = 0; * 队列空:head == tail; * 队列满:(tail + 1) % MaxSize == head; * 元素数:num = (tail - head + MaxSize) % MaxSize * */ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include "circularQueue.h" //判断循环队列是否为空 int IsQueEmpty(P_CIRCULAR_QUEUE cQue) { return cQue->cqHead == cQue->cqTail; } //判断循环队列是否满 int IsQueFull(P_CIRCULAR_QUEUE cQue) { //为了区分队空的情况和队满的情况,使用+1来空出一个数据 return (cQue->cqTail + 1) % cQue->maxSize == cQue->cqHead; } //获取循环队列的大小 int getQueueSize(P_CIRCULAR_QUEUE cQue) { cQue->size = (cQue->cqTail - cQue->cqHead + cQue->maxSize) % cQue->maxSize; printf("cqTail[%d], cqHead[%d], size[%d] ", cQue->cqTail, cQue->cqHead, cQue->size); return cQue->size; } //获取循环队列队首的位置 int getQueueHead(P_CIRCULAR_QUEUE cQue) { return cQue->cqHead; } //获取循环队列队首元素 int getQueueHeadData(P_CIRCULAR_QUEUE cQue) { return cQue->data[cQue->cqHead]; } //获取循环队列队尾的位置 int getQueueTail(P_CIRCULAR_QUEUE cQue) { return cQue->cqTail; } //获取循环队列队首元素 int getQueueTailData(P_CIRCULAR_QUEUE cQue) { return cQue->data[cQue->cqTail]; } //初始化循环队列 void InitCircularQue(P_CIRCULAR_QUEUE cQue, int maxsize) { printf("cque size =%zu ", sizeof(*cQue)); cQue->data = (int*)malloc(sizeof(int)*maxsize); //memset(cQue, 0, sizeof(*cQue)); cQue->cqTail = 0; cQue->cqHead = 0; cQue->size = 0; cQue->maxSize = maxsize; printf("cqHead[%d], cqTail[%d], maxSize[%d] ", cQue->cqHead, cQue->cqTail, cQue->maxSize); } //向循环队列中插入元素 void enterCircularQue(P_CIRCULAR_QUEUE cQue, int elem) { if(IsQueFull(cQue)) { printf("Elem %d can't push to CircularQueue %p (Full)! ", elem, cQue); return; } //cQue->data[cQue->cqTail] = elem; int *p = cQue->data; p[cQue->cqTail] = elem; cQue->cqTail = (cQue->cqTail + 1)%cQue->maxSize; printf("cqTail ==%d ", cQue->cqTail); } //从循环队列中取数据 int leaveCircularQue(P_CIRCULAR_QUEUE cQue) { if(IsQueEmpty(cQue)) { printf("Queue %p is Empty! ", cQue); return -1; } int elem = cQue->data[cQue->cqHead]; cQue->cqHead = (cQue->cqHead + 1)%cQue->maxSize; printf("cqHead == %d ", cQue->cqHead); return elem; } //显示队列中的所有元素 void ShowQue(P_CIRCULAR_QUEUE cQue) { if(IsQueEmpty(cQue)) { printf("Queue %p is Empty! ", cQue); return ; } printf("CircularQueue Element: "); int elemIdx = cQue->cqHead; while((elemIdx % cQue->maxSize) != cQue->cqTail) printf("%d ", cQue->data[(elemIdx++) % cQue->maxSize]); printf(" "); } void delQue(P_CIRCULAR_QUEUE cQue) { cQue->cqTail = cQue->cqHead = 0; FREE(cQue->data); }
main.c
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> #include "circularQueue.h" #define P_COUNT 5 //producer NO. #define C_COUNT 5 //NO. #define MAX 50 //缓冲区的的大小 CIRCULAR_QUEUE gcQue; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //锁住缓冲区 /*队列满的时候,阻塞生产这线程,队列空时阻塞消费者线程*/ pthread_cond_t notFull = PTHREAD_COND_INITIALIZER; // pthread_cond_t notEmpty = PTHREAD_COND_INITIALIZER; typedef struct{ char buffer[MAX]; int count; }Buffer; Buffer share = {"", 0}; char ch = 'A'; void *producer(void *arg) { int id = *(int *)arg; printf("[%d] Producer : starting ", id); //while(ch != 'K') while(1) { pthread_mutex_lock(&mutex); while(IsQueFull(&gcQue)){ pthread_cond_wait(¬Full, &mutex); printf("[%d] producer wating for not full signal ", id); } enterCircularQue(&gcQue, 100); //printf("[%d] Producer: put [%d] char[%c] ", id, share.count-1, ch ); pthread_cond_signal(¬Empty); pthread_mutex_unlock(&mutex); sleep(1); } sleep(1); printf("Produce: Exiting "); } void *consumer(void *junk) { int id = *(int *)junk; printf(" [%d] Consumer : starting ", id); //while (ch != 'K') while (1) { pthread_mutex_lock(&mutex); printf(" [%d] Consumer : Waiting ", id); while(IsQueEmpty(&gcQue)){ pthread_cond_wait(¬Empty, &mutex); //条件不成立释放锁. printf(" [%d] Consumer wating for not empty signal ", id); } leaveCircularQue(&gcQue); pthread_cond_signal(¬Full); pthread_mutex_unlock(&mutex); sleep(1); } } int main() { int i; pthread_t t_read[C_COUNT], t_write[P_COUNT]; InitCircularQue(&gcQue, MAX+1); int *pId=(int *)malloc(sizeof(int)*P_COUNT); int *cId=(int *)malloc(sizeof(int)*C_COUNT); for(i = 0; i < P_COUNT; ++i){ pId[i] = i; pthread_create(&t_write[i], NULL, (void *)producer, (void *)&pId[i]); } for(i = 0; i < C_COUNT; ++i){ cId[i] = i; pthread_create(&t_read[i], NULL, (void *) consumer, (void *)&cId[i]); } for(i = 0; i < P_COUNT; ++i){ pthread_join(t_read[i], NULL); } for(i = 0; i < C_COUNT; ++i){ pthread_join(t_write[i], NULL); } pthread_mutex_destroy(&mutex); pthread_cond_destroy(¬Full); pthread_cond_destroy(¬Empty); delQue(&gcQue); return 0; }
生产者消费者问题也缓冲区无界的情况,一般链表就是实现缓冲区的一种方法,可以根据用链表实现队列的功能
来修改临界区代码,类似上面循环队列.