在C++面试中,如果需要展示生产者-消费者模型的代码,以下是一个使用标准库中的std::mutex
、std::condition_variable
以及std::unique_lock
实现的示例:
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx; // 互斥锁
std::condition_variable cv; // 条件变量
std::vector<int> buffer; // 共享缓冲区
const int MAX_SIZE = 10; // 缓冲区最大容量
// 生产者函数
void producer(int id) {
for (int i = 0; i < 10; ++i) {
std::unique_lock<std::mutex> lock(mtx);
buffer.push_back(i * id); // 生产数据
std::cout << "Producer " << id << " produced: " << i * id << std::endl;
cv.notify_one(); // 唤醒一个等待的消费者
lock.unlock(); // 显式解锁,虽然unique_lock在析构时会自动解锁
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟生产所需时间
}
}
// 消费者函数
void consumer(int id) {
for (;;) {
std::unique_lock<std::mutex> lock(mtx);
while (buffer.empty()) {
cv.wait(lock); // 如果缓冲区为空,消费者等待
}
int data = buffer.front();
buffer.erase(buffer.begin()); // 消费数据
std::cout << "Consumer " << id << " consumed: " << data << std::endl;
lock.unlock(); // 显式解锁
std::this_thread::sleep_for(std::chrono::milliseconds(150)); // 模拟消费所需时间
}
}
int main() {
std::thread producers[2], consumers[2];
// 启动生产者线程
for (int i = 0; i < 2; ++i) {
producers[i] = std::thread(producer, i + 1);
}
// 启动消费者线程
for (int i = 0; i < 2; ++i) {
consumers[i] = std::thread(consumer, i + 1);
}
// 等待生产者线程结束
for (int i = 0; i < 2; ++i) {
producers[i].join();
}
// 消费者线程应该在适当的时候退出,这里为了示例简单,我们让它们一直运行
// 在实际应用中,应该有一个机制来优雅地停止消费者线程
return 0;
}
这段代码中的关键点包括:
- 使用
std::mutex
来同步对共享缓冲区buffer
的访问。 - 使用
std::condition_variable
来同步生产者和消费者的行为。生产者生产数据后通知消费者,消费者在缓冲区空时等待生产者。 -
producer
函数模拟生产数据并放入缓冲区,然后唤醒一个等待的消费者。 -
consumer
函数模拟消费数据,从缓冲区取出数据并处理。如果缓冲区为空,则等待生产者的通知。 -
main
函数中创建并启动了生产者和消费者线程,并等待生产者线程结束。消费者线程在这个示例中会无限循环,但在实际应用中应该有一个退出条件。
面试回答示例:
"在C++中,我们可以使用std::mutex
和std::condition_variable
来实现生产者-消费者模型。std::mutex
用于保护共享资源,确保同时只有一个线程可以访问缓冲区。std::condition_variable
用于在生产者生产数据后通知消费者,以及在消费者等待数据时挂起。生产者将数据放入缓冲区,并使用notify_one
唤醒一个等待的消费者。消费者在缓冲区空时使用wait
挂起,直到被生产者通知。这个模型确保了线程安全和有效的线程间通信。"