生产者-消费者问题(Producer-Consumer Problem)是操作系统、并发编程和数据结构课程中的经典案例。它描述了两个角色:生产者负责生产数据并放入缓冲区,消费者则从缓冲区取出数据进行消费。两者通过一个共享的缓冲区(通常为队列)进行协作,既要保证数据的正确流转,又要避免资源竞争和数据丢失。
本篇文章将以循环队列为核心,详细讲解如何用 C 语言实现一个简洁、易懂的生产者-消费者模型。本文适合数据结构初学者和对并发编程感兴趣的读者。
循环队列是一种高效利用数组空间的队列实现方式。其结构体如下:
#define QUEUE_MAX_SIZE 10
typedef struct
{
int data[QUEUE_MAX_SIZE]; // 存储产品的数组
int front; // 队头指针,指向下一个要被消费的元素
int rear; // 队尾指针,指向下一个要被生产的位置
int count; // 当前队列元素个数
} Queue;
data
:用于存储产品(这里用整数模拟产品)。front
:队头指针,指向下一个要被消费的元素。rear
:队尾指针,指向下一个要被生产的位置。count
:当前队列中的产品数量。void queue_init(Queue *q);
int queue_is_empty(Queue *q);
int queue_is_full(Queue *q);
int queue_enqueue(Queue *q, int item);
int queue_dequeue(Queue *q, int *item);
void queue_print(Queue *q);
void queue_init(Queue *q)
{
q->front = 0;
q->rear = 0;
q->count = 0;
}
int queue_is_empty(Queue *q)
{
return q->count == 0;
}
int queue_is_full(Queue *q)
{
return q->count == QUEUE_MAX_SIZE;
}
int queue_enqueue(Queue *q, int item)
{
if (queue_is_full(q))
return 0;
q->data[q->rear] = item;
q->rear = (q->rear + 1) % QUEUE_MAX_SIZE;
q->count++;
return 1;
}
int queue_dequeue(Queue *q, int *item)
{
if (queue_is_empty(q))
return 0;
*item = q->data[q->front];
q->front = (q->front + 1) % QUEUE_MAX_SIZE;
q->count--;
return 1;
}
void queue_print(Queue *q)
{
printf("Queue: [");
for (int i = 0, idx = q->front; i < q->count; i++, idx = (idx + 1) % QUEUE_MAX_SIZE)
{
printf("%d ", q->data[idx]);
}
printf("] (count=%d)\n", q->count);
}
void producer(Queue *q)
{
if (queue_is_full(q))
{
printf("Queue is full, cannot produce.\n");
return;
}
int data = rand() % 100; // 生成一个随机数作为产品
queue_enqueue(q, data);
printf("Produced: %d\n", data);
}
void consumer(Queue *q)
{
if (queue_is_empty(q))
{
printf("Queue is empty, cannot consume.\n");
return;
}
int data;
queue_dequeue(q, &data);
printf("Consumed: %d\n", data);
}
主函数通过命令行交互,模拟生产和消费过程:
int main(void)
{
Queue q;
queue_init(&q);
char cmd;
printf("Simple Producer-Consumer Simulation (Queue Version)\n");
printf("p: produce, c: consume, q: quit\n");
while (1)
{
queue_print(&q);
printf("Enter command (p/c/q): ");
scanf(" %c", &cmd);
if (cmd == 'p')
{
producer(&q);
}
else if (cmd == 'c')
{
consumer(&q);
}
else if (cmd == 'q')
{
break;
}
else
{
printf("Invalid command.\n");
}
}
return 0;
}
p
生产产品,c
消费产品,q
退出程序。#include
#include
#include
#include
#define QUEUE_MAX_SIZE 10
typedef struct
{
int data[QUEUE_MAX_SIZE];
int front;
int rear;
int count;
} Queue;
void queue_init(Queue *q)
{
q->front = 0;
q->rear = 0;
q->count = 0;
}
int queue_is_empty(Queue *q)
{
return q->count == 0;
}
int queue_is_full(Queue *q)
{
return q->count == QUEUE_MAX_SIZE;
}
int queue_enqueue(Queue *q, int item)
{
if (queue_is_full(q))
return 0;
q->data[q->rear] = item;
q->rear = (q->rear + 1) % QUEUE_MAX_SIZE;
q->count++;
return 1;
}
int queue_dequeue(Queue *q, int *item)
{
if (queue_is_empty(q))
return 0;
*item = q->data[q->front];
q->front = (q->front + 1) % QUEUE_MAX_SIZE;
q->count--;
return 1;
}
void queue_print(Queue *q)
{
printf("Queue: [");
for (int i = 0, idx = q->front; i < q->count; i++, idx = (idx + 1) % QUEUE_MAX_SIZE)
{
printf("%d ", q->data[idx]);
}
printf("] (count=%d)\n", q->count);
}
void producer(Queue *q)
{
if (queue_is_full(q))
{
printf("Queue is full, cannot produce.\n");
return;
}
int data = rand() % 100; // 生成一个随机数作为产品
queue_enqueue(q, data);
printf("Produced: %d\n", data);
}
void consumer(Queue *q)
{
if (queue_is_empty(q))
{
printf("Queue is empty, cannot consume.\n");
return;
}
int data;
queue_dequeue(q, &data);
printf("Consumed: %d\n", data);
}
int main(void)
{
Queue q;
queue_init(&q);
char cmd;
printf("Simple Producer-Consumer Simulation (Queue Version)\n");
printf("p: produce, c: consume, q: quit\n");
while (1)
{
queue_print(&q);
printf("Enter command (p/c/q): ");
scanf(" %c", &cmd);
if (cmd == 'p')
{
producer(&q);
}
else if (cmd == 'c')
{
consumer(&q);
}
else if (cmd == 'q')
{
break;
}
else
{
printf("Invalid command.\n");
}
}
return 0;
}
将上述代码保存为 produce_consumer.c
文件。
gcc produce_consumer.c -o produce_consumer
produce_consumer.exe
gcc produce_consumer.c -o produce_consumer
./produce_consumer
Simple Producer-Consumer Simulation (Queue Version)
p: produce, c: consume, q: quit
Queue: [] (count=0)
Enter command (p/c/q): p
Produced: 42
Queue: [42 ] (count=1)
Enter command (p/c/q): p
Produced: 17
Queue: [42 17 ] (count=2)
Enter command (p/c/q): c
Consumed: 42
Queue: [17 ] (count=1)
Enter command (p/c/q): q
本文详细介绍了如何用循环队列实现生产者-消费者模型,涵盖了队列的定义、操作函数、生产者与消费者实现、主函数交互流程以及完整代码和运行方法。通过本例,你可以深入理解队列数据结构的实际应用,以及生产者-消费者问题的基本思想。
如需进一步学习多线程并发、信号量等高级内容,欢迎继续关注相关专题!