本文讲解如何使用C语言来解决生产者与消费者问题。
相关在线编辑网站:https://www.ideone.com/whPQYr
编写一个简单的生产者-消费者(producer-consumer)模型,其中包含一个生产者进程和一个消费者进程以及一个共享的缓冲区(使用队列或环形缓冲区)。生产者会更新缓存数据,而消费者则会使用该内存,程序按照如下规则运行:
PV操作(信号量机制)是一种常见的用于线程同步和互斥的解决方案。这里简要介绍如何使用 PV 操作来实现给定问题的生产者/消费者模型。
首先创建两个信号灯 empty 和 full。empty 表示空缓存区数量,full 表示有数据可用的缓存区数量。其中 empty 的初始值应为缓存队列的大小,而 full 的初始值则应为 0。
对于生产者和消费者:
在每次添加或读取信息成功时,在操作完成后,都需要调用 sem_wait() 在更改数据之前等待空闲空间或可用项。
具体题解代码如下:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <semaphore.h>
#define QUEUE_SIZE 10 // 定义缓存区大小
int buffer[QUEUE_SIZE]; // 缓存区数组
int in = 0, out = 0; // 输入和输出指针
sem_t full, empty; // 初始化计数信号灯
pthread_mutex_t lock; // 声明互斥锁
// 生产者线程函数
void *producer(void *arg){
while (1) {
int new_item = some_producing_function(); // 生成新产品的函数
sem_wait(&empty); // 降低 empty 的值,等待可用缓存空间
pthread_mutex_lock(&lock); // 加锁
buffer[in] = new_item; // 写入缓存区
in = (in + 1) % QUEUE_SIZE; // 更新输入队列指针
printf("Produced %d\n", new_item);
pthread_mutex_unlock(&lock); // 解锁
sem_post(&full); // 提高 full 的值,增加可消费产品数量
sleep(2); // 随机等待一段时间, 然后再生产下一个数据
}
}
// 消费者线程函数
void *consumer(void *arg){
while (1) {
sem_wait(&full); //减小 full 的值,等待有可消费的产品
pthread_mutex_lock(&lock); //加锁
int consumed_item = buffer[out]; // 从缓存区读取
out = (out+1) % QUEUE_SIZE; // 更新输出队列指针
printf("Consumed %d\n", consumed_item);
pthread_mutex_unlock(&lock); //解锁
sem_post(&empty); //提高 empty 的值,增加可用空间
sleep(3); // 等待一段时间再进行下一次消费操作
}
}
int main(int argc, char const **argv)
{
sem_init(&empty, 0, QUEUE_SIZE); //初始化 empty信号灯,用于追踪缓存区为空的使用情况。其初始值为缓存队列的大小
sem_init(&full, 0, 0); // full信号灯 跟踪有多少产品已经被生产
pthread_mutex_init(&lock, NULL); // 初始化互斥锁
pthread_t producer_thread, consumer_thread;
pthread_create(&producer_thread, NULL, &producer, NULL); //启动生产者线程
pthread_create(&consumer_thread, NULL, &consumer, NULL); //启动消费者线程
pthread_join(producer_thread, NULL);
pthread_join(consumer_thread, NULL);
sem_destroy(&empty); // 销毁两个信号灯
sem_destroy(&full);
pthread_mutex_destroy(&lock); //销毁 mutex 执行完成之后
return 0;
}在该程序中,使用 PV 机制和互斥量来控制对缓存区的并发访问,保证了两个线程能够安全地使用共享数据组成的缓冲区。具体实现包括:
这些机制的正确应用确保了必要的同步,并使程序不会数据竞争。
运行结果分析: 由于这是一个生产者-消费者模型的程序,最终的运行结果是不确定的。在理想情况下,该程序将会无限循环地生产产品并消费产品,并且输出如下所示:
Produced 1 Consumed 1 Produced 2 Consumed 2 Produced 3 Consumed 3 …………
但实际运行过程中,可能会出现以下情况:
因此,最终的结果将取决于各种线程之间的执行顺序和时间分配。