生产者消费者问题例题及详解
生产者消费者问题是一个经典的并发问题,涉及到两个独立的线程:生产者和消费者。
生产者生产物品,消费者消费物品。
生产者、消费者共享一个公共的固定大小的缓冲区。
以下是一个简单的生产者消费者问题的例子:
假设有一个固定大小的缓冲区,大小为N。
生产者负责生成数据放入缓冲区,而消费者负责从缓冲区取出数据并处理。
1. 当缓冲区为空时,消费者被阻塞,等待生产者生产数据。
2. 当缓冲区满时,生产者被阻塞,等待消费者消费数据。
3. 缓冲区的每个元素只能被消费一次。
4. 缓冲区是循环使用的,即当缓冲区的最后一个元素被消费后,下一个元素将是缓冲区的第一个元素。
问题:如何实现这个生产者消费者模型?
解答:可以使用条件变量和互斥锁来实现这个模型。
首先,定义一个缓冲区数组和一个计数器变量来跟踪缓冲区的使用情况。
然后,定义两个条件变量:一个用于生产者等待缓冲区非空,另一个用于消费者等待缓冲区非空。
最后,使用互斥锁来保护对缓冲区和计数器的访问。
以下是使用C++实现的代码示例:
```cpp
include <iostream>
include <thread>
include <mutex>
include <condition_variable>
const int N = 5; // 缓冲区大小
int buffer[N]; // 缓冲区数组
int count = 0; // 计数器变量,表示缓冲区的使用情况
std::mutex mutex; // 互斥锁
std::condition_variable cv_prod; // 生产者等待条件变量
std::condition_variable cv_cons; // 消费者等待条件变量
void producer() {
for (int i = 0; i < N 2; i++) {
std::unique_lock<std::mutex> lock(mutex);
cv_(lock, []{ return count < N; }); // 等待缓冲区非空
buffer[count] = i; // 生产数据放入缓冲区
std::cout << "Producer produced " << i << std::endl;
count++; // 更新计数器变量
if (count == N) count = 0; // 循环使用缓冲区
cv__one(); // 通知消费者消费数据
}
}
void consumer() {
for (int i = 0; i < N 2; i++) {
std::unique_lock<std::mutex> lock(mutex);
cv_(lock, []{ return count > 0; }); // 等待缓冲区非空
int data = buffer[count]; // 从缓冲区取出数据并处理 std::cout << "Consumer consumed " << data << std::endl;
count--; // 更新计数器变量
if (count == -1) count = N - 1; // 循环使用缓冲区
cv__one(); // 通知生产者生产数据
}
}
int main() {
std::thread prod(producer); // 创建生产者线程 std::thread cons(consumer); // 创建消费者线程 (); // 等待生产者线程结束
(); // 等待消费者线程结束
return 0;
}
```。