最简单的生产者-消费者模式实现
生产者-消费者模式
这是多线程开发中一种常见的设计模式,用于解决数据生产和消费速度不一致的问题。
在生产者和消费者二者之间增加一层缓冲区,生产者只需要关心缓冲区是否还能存放数据,不需要等待消费者处理完;同样消费者只关注缓冲区是否还存有数据。
也就是说,这样的模型可以带来最显著的优势是:生产者和消费者完全解耦合,可以独立开发和扩展。如你可以增加并发数、支持分布式开发等。
如何实现?
分三部分考虑:
-
对于缓冲区:先生产的数据要被先消费,自然想到缓冲区用队列结构实现。缓冲区有大小限制,你不能在满了之后继续生产数据。当然也不能在空的时候消费数据。
-
对于生产者:在往缓冲区存放数据前,判断是否已满。当缓冲区已满时,使用条件变量等待数据被拿取,直到能够继续存放数据。存完数据后通知消费者。
-
对于消费者:在拿去缓冲区数据时,判断是否为空。当缓冲区为空时,使用条件变量等到新数据存放,直到能够拿取数据。拿完后通知生产者。
代码实现
假定缓冲区存放 int 型数据,缓冲区大小为 5 。
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
std::mutex mtx;
std::condition_variable cv;
std::queue<int> que;
const int MAX_SIZE = 5;
void producer() {
for (int i = 0; i < 10; ++i) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return que.size() < MAX_SIZE; });
que.push(i);
std::cout << "produce " << i << "/" << que.size() << std::endl;
cv.notify_all();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
void consumer() {
for (int i = 0; i < 10; ++i) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return !que.empty(); });
int val = que.front();
que.pop();
std::cout << "consume " << i << "/" << que.size() << std::endl;
cv.notify_all();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
int main() {
std::thread p(producer);
std::thread c(consumer);
p.join();
c.join();
return 0;
}
下次面试官让我使用 C++ 实现生产者-消费者模型,可以直接照着这个写,而不是陷入尴尬的境地 :<