一组生产者,一组消费者,公用n个环形缓冲区的生产者和消费者问题
时间: 2023-11-06 13:05:58 浏览: 37
这是一个典型的多生产者、多消费者问题,可以使用多线程和多缓冲区来解决。下面是一个简单的实现:
```c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define BUFFER_SIZE 10 // 缓冲区大小
#define PRODUCER_NUM 2 // 生产者数量
#define CONSUMER_NUM 2 // 消费者数量
#define PRODUCE_TIMES 20 // 生产者生产次数
#define CONSUME_TIMES 20 // 消费者消费次数
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 互斥锁
pthread_cond_t *full; // 缓冲区满的条件变量数组
pthread_cond_t *empty; // 缓冲区空的条件变量数组
int **buffer; // 缓冲区数组
int *buffer_index; // 缓冲区当前索引的位置数组
void *producer(void *arg) {
int id = *(int *)arg;
int i, j, data;
for (i = 0; i < PRODUCE_TIMES; i++) {
data = rand() % 1000; // 生成随机数作为生产者产生的数据
pthread_mutex_lock(&mutex); // 上锁
while (buffer_index[id] == BUFFER_SIZE) { // 缓冲区已满,则等待
pthread_cond_wait(&full[id], &mutex);
}
buffer[id][buffer_index[id]++] = data; // 将数据存入缓冲区
printf("producer %d produced data %d\n", id, data);
pthread_cond_signal(&empty[id]); // 发出缓冲区非空的信号
pthread_mutex_unlock(&mutex); // 解锁
sleep(rand() % 3); // 生产者休息一段时间
}
pthread_exit(NULL);
}
void *consumer(void *arg) {
int id = *(int *)arg;
int i, j, data;
for (i = 0; i < CONSUME_TIMES; i++) {
pthread_mutex_lock(&mutex); // 上锁
while (buffer_index[id] == 0) { // 缓冲区为空,则等待
pthread_cond_wait(&empty[id], &mutex);
}
data = buffer[id][--buffer_index[id]]; // 从缓冲区取出数据
printf("consumer %d consumed data %d\n", id, data);
pthread_cond_signal(&full[id]); // 发出缓冲区非满的信号
pthread_mutex_unlock(&mutex); // 解锁
sleep(rand() % 3); // 消费者休息一段时间
}
pthread_exit(NULL);
}
int main() {
pthread_t producer_thread[PRODUCER_NUM], consumer_thread[CONSUMER_NUM];
int i, j;
srand(time(NULL)); // 初始化随机数种子
full = (pthread_cond_t *)malloc(sizeof(pthread_cond_t) * PRODUCER_NUM); // 创建条件变量数组
empty = (pthread_cond_t *)malloc(sizeof(pthread_cond_t) * CONSUMER_NUM); // 创建条件变量数组
buffer = (int **)malloc(sizeof(int *) * PRODUCER_NUM); // 创建缓冲区数组
buffer_index = (int *)malloc(sizeof(int) * PRODUCER_NUM); // 创建缓冲区当前索引的位置数组
for (i = 0; i < PRODUCER_NUM; i++) {
buffer[i] = (int *)malloc(sizeof(int) * BUFFER_SIZE); // 创建缓冲区
buffer_index[i] = 0; // 初始化缓冲区当前索引的位置
pthread_cond_init(&full[i], NULL); // 初始化条件变量
}
for (i = 0; i < CONSUMER_NUM; i++) {
pthread_cond_init(&empty[i], NULL); // 初始化条件变量
}
int *producer_id = (int *)malloc(sizeof(int) * PRODUCER_NUM);
int *consumer_id = (int *)malloc(sizeof(int) * CONSUMER_NUM);
for (i = 0; i < PRODUCER_NUM; i++) {
producer_id[i] = i;
pthread_create(&producer_thread[i], NULL, producer, &producer_id[i]); // 创建生产者线程
}
for (i = 0; i < CONSUMER_NUM; i++) {
consumer_id[i] = i;
pthread_create(&consumer_thread[i], NULL, consumer, &consumer_id[i]); // 创建消费者线程
}
for (i = 0; i < PRODUCER_NUM; i++) {
pthread_join(producer_thread[i], NULL); // 等待生产者线程结束
pthread_cond_destroy(&full[i]); // 销毁条件变量
free(buffer[i]); // 释放缓冲区内存
}
for (i = 0; i < CONSUMER_NUM; i++) {
pthread_join(consumer_thread[i], NULL); // 等待消费者线程结束
pthread_cond_destroy(&empty[i]); // 销毁条件变量
}
free(full); // 释放条件变量数组内存
free(empty); // 释放条件变量数组内存
free(buffer); // 释放缓冲区数组内存
free(buffer_index); // 释放缓冲区当前索引的位置数组内存
free(producer_id);
free(consumer_id);
pthread_mutex_destroy(&mutex); // 销毁互斥锁
return 0;
}
```
在这个例子中,有两组生产者和两组消费者,它们共享n个环形缓冲区。每个生产者和消费者线程都有一个id变量,用于区分不同的线程。为了保证生产者和消费者的同步,我们使用了互斥锁和条件变量。
当生产者试图往缓冲区中存入数据时,如果缓冲区已满,则生产者会等待,直到消费者取出数据后缓冲区非满;当消费者试图从缓冲区中取出数据时,如果缓冲区为空,则消费者会等待,直到生产者存入数据后缓冲区非空。这样就保证了生产者和消费者的同步。