【c++】生产者与消费者问题

本文详细介绍了一种经典的多线程同步问题——生产者消费者模式的实现。通过环形队列和条件变量,展示了单个生产者与单个消费者、多个生产者与单个消费者、单个生产者与多个消费者以及多个生产者与多个消费者的四种场景下如何进行线程间的同步与通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单个生产者和单个消费者

#include <iostream>
#include <mutex>
#include <condition_variable>
#include <Windows.h>

using namespace std;

const int ITEMREPOSITORY_MAXSIZE = 10;
const int ITEMTOPRODUCE_COUNT = 100;

//使用环形队列
struct ItemRepository
{
	int itemBuffer[ITEMREPOSITORY_MAXSIZE];
	size_t readPosition;
	size_t writePosition;
	std::mutex mtx; //仓库锁
	std::condition_variable repoNotFull; //仓库满时条件变量
	std::condition_variable repoNotEmpty; //仓库空时条件变量
};

void InitRepository(ItemRepository *ir)
{
	ir->readPosition = 0;
	ir->writePosition = 0;
}

void ProduceItem(ItemRepository *ir, int item)
{
	std::unique_lock<std::mutex > lock(ir->mtx);
	//当仓库满时,阻塞自己,等待消费者消费
	while ((ir->writePosition + 1) % ITEMREPOSITORY_MAXSIZE == ir->readPosition)
	{
		cout << "Productor is waiting an empty slot..." << endl;
		ir->repoNotFull.wait(lock);
	}
	//有空位,往仓库放入产品
	ir->itemBuffer[ir->writePosition] = item;
	++ir->writePosition;
	//如果写入位置超出环形队列大小上限,移动到开始位置
	if (ir->writePosition >= ITEMREPOSITORY_MAXSIZE)
	{
		ir->writePosition = 0;
	}
	//通知消费者仓库不为空,快来消费
	ir->repoNotEmpty.notify_all();
	lock.unlock();
}

int ConsumeItem(ItemRepository *ir)
{
	std::unique_lock<mutex> lock(ir->mtx);
	//如果仓库为空,阻塞自己,等待生产者放入产品
	while (ir->readPosition == ir->writePosition)
	{
		cout << "repo is empty, consume is waiting a item..." << endl;
		ir->repoNotEmpty.wait(lock);
	}
	//仓库不为空,开始消费产品
	int item = ir->itemBuffer[ir->readPosition];
	++ir->readPosition;
	if (ir->readPosition >= ITEMREPOSITORY_MAXSIZE)
	{
		ir->readPosition = 0;
	}
	//通知生产者,我消耗了产品,你赶快再生产
	ir->repoNotFull.notify_all();
	lock.unlock();
	return item;
}

void ProduceTask(ItemRepository *ir)
{
	cout << "start to produce item!" << endl;
	for (int i = 0; i <= ITEMTOPRODUCE_COUNT; ++i)
	{
	    //Sleep(100); //可以观察仓库为空时输出情况
		ProduceItem(ir, i);
	}
	cout << "produce end!" << endl;
}

void ConsumeTask(ItemRepository *ir)
{
	cout << "start to consume!" << endl;
	while (true)
	{
		int item = ConsumeItem(ir);
		cout << "I'm is consuming " << item << "th item!" << endl;
		if (item == ITEMTOPRODUCE_COUNT)
		{
			break;
		}
	}
	cout << "consume all productor, cool!" << endl;
}

int main()
{
	ItemRepository gItemRepository;
	InitRepository(&gItemRepository);
	std::thread producer(ProduceTask, &gItemRepository);
	std::thread consumer(ConsumeTask, &gItemRepository);
	producer.join();
	consumer.join();
	getchar();
	return EXIT_SUCCESS;
}

多个生产者和单个消费者

#include <iostream>
#include <mutex>
#include <condition_variable>
#include <Windows.h>

using namespace std;

const int ITEMREPOSITORY_MAXSIZE = 10;
const int ITEMTOPRODUCE_COUNT = 100;

//使用环形队列
//生产者计数器和锁也可以放仓库外
struct ItemRepository
{
	int itemBuffer[ITEMREPOSITORY_MAXSIZE];
	size_t readPosition;
	size_t writePosition;
	int produceCounter;//生产者计数器
	std::mutex mtx; //仓库锁
	std::mutex produceCounterMutex;//生产者计数锁
	std::condition_variable repoNotFull; //仓库满时条件变量
	std::condition_variable repoNotEmpty; //仓库空时条件变量
};

void InitRepository(ItemRepository *ir)
{
	ir->readPosition = 0;
	ir->writePosition = 0;
	ir->produceCounter = 0;
}

void ProduceItem(ItemRepository *ir, int item)
{
	std::unique_lock<std::mutex > lock(ir->mtx);
	//当仓库满时,阻塞自己,等待消费者消费
	while ((ir->writePosition + 1) % ITEMREPOSITORY_MAXSIZE == ir->readPosition)
	{
		cout << "Productor is waiting an empty slot..." << endl;
		ir->repoNotFull.wait(lock);
	}
	//有空位,往仓库放入产品
	ir->itemBuffer[ir->writePosition] = item;
	++ir->writePosition;
	//如果写入位置超出环形队列大小上限,移动到开始位置
	if (ir->writePosition >= ITEMREPOSITORY_MAXSIZE)
	{
		ir->writePosition = 0;
	}
	//通知消费者仓库不为空,快来消费
	ir->repoNotEmpty.notify_all();
	lock.unlock();
}

int ConsumeItem(ItemRepository *ir)
{
	std::unique_lock<mutex> lock(ir->mtx);
	//如果仓库为空,阻塞自己,等待生产者放入产品
	while (ir->readPosition == ir->writePosition)
	{
		cout << "repo is empty, consume is waiting a item..." << endl;
		ir->repoNotEmpty.wait(lock);
	}
	//仓库不为空,开始消费产品
	int item = ir->itemBuffer[ir->readPosition];
	++ir->readPosition;
	if (ir->readPosition >= ITEMREPOSITORY_MAXSIZE)
	{
		ir->readPosition = 0;
	}
	//通知生产者,我消耗了产品,你赶快再生产
	ir->repoNotFull.notify_all();
	lock.unlock();
	return item;
}

void ProduceTask(ItemRepository *ir)
{
	bool isExit = false;
	cout << "thread [" << this_thread::get_id() << "] start to produce item!" << endl;
	while (true)
	{
		//每个线程阻塞自己一秒,否则其他线程有可能抢占不到锁而变成单生产者
		this_thread::sleep_for(chrono::seconds(1));
		std::unique_lock<std::mutex> lock(ir->produceCounterMutex);
		if (ir->produceCounter < ITEMTOPRODUCE_COUNT)
		{
			++ir->produceCounter;
			ProduceItem(ir, ir->produceCounter);
			cout << "thread [" << this_thread::get_id() << "] has produced "<< ir->produceCounter << "th item!" << endl;
		}
		else 
		{
			isExit = true;
		}	
		if (isExit)
		{
			lock.unlock();
			break;
		}
		lock.unlock();
	}
	cout << "thread [" << this_thread::get_id() << "] produce end!" << endl;
}

void ConsumeTask(ItemRepository *ir)
{
	cout << "start to consume!" << endl;
	while (true)
	{
		int item = ConsumeItem(ir);
		cout << "I'm is consuming " << item << "th item!" << endl;
		if (item == ITEMTOPRODUCE_COUNT)
		{
			break;
		}
	}
	cout << "consume all productor, cool!" << endl;
}

int main()
{
	ItemRepository gItemRepository;
	InitRepository(&gItemRepository);
	std::thread producerOne(ProduceTask, &gItemRepository);
	std::thread producerTwo(ProduceTask, &gItemRepository);
	std::thread consumer(ConsumeTask, &gItemRepository);
	producerOne.join();
	producerTwo.join();
	consumer.join();
	getchar();
	return EXIT_SUCCESS;
}

单个生产者和多个消费者

#include <iostream>
#include <mutex>
#include <condition_variable>
#include <Windows.h>
#include <chrono>

using namespace std;

const int ITEMREPOSITORY_MAXSIZE = 10;
const int ITEMTOPRODUCE_COUNT = 100;

//使用环形队列
struct ItemRepository
{
	int itemBuffer[ITEMREPOSITORY_MAXSIZE];
	size_t readPosition;
	size_t writePosition;
	int consumeCounter;
	std::mutex mtx; //仓库锁
	std::mutex consumeCounterMutex;
	std::condition_variable repoNotFull; //仓库满时条件变量
	std::condition_variable repoNotEmpty; //仓库空时条件变量
};

void InitRepository(ItemRepository *ir)
{
	ir->readPosition = 0;
	ir->writePosition = 0;
	ir->consumeCounter = 0;
}

void ProduceItem(ItemRepository *ir, int item)
{
	std::unique_lock<std::mutex > lock(ir->mtx);
	//当仓库满时,阻塞自己,等待消费者消费
	while ((ir->writePosition + 1) % ITEMREPOSITORY_MAXSIZE == ir->readPosition)
	{
		cout << "Productor is waiting an empty slot..." << endl;
		ir->repoNotFull.wait(lock);
	}
	//有空位,往仓库放入产品
	ir->itemBuffer[ir->writePosition] = item;
	++ir->writePosition;
	//如果写入位置超出环形队列大小上限,移动到开始位置
	if (ir->writePosition >= ITEMREPOSITORY_MAXSIZE)
	{
		ir->writePosition = 0;
	}
	//通知消费者仓库不为空,快来消费
	ir->repoNotEmpty.notify_all();
	lock.unlock();
}

int ConsumeItem(ItemRepository *ir)
{
	std::unique_lock<mutex> lock(ir->mtx);
	//如果仓库为空,阻塞自己,等待生产者放入产品
	while (ir->readPosition == ir->writePosition)
	{
		cout << "repo is empty, consume is waiting a item..." << endl;
		ir->repoNotEmpty.wait(lock);
	}
	//仓库不为空,开始消费产品
	int item = ir->itemBuffer[ir->readPosition];
	++ir->readPosition;
	if (ir->readPosition >= ITEMREPOSITORY_MAXSIZE)
	{
		ir->readPosition = 0;
	}
	//通知生产者,我消耗了产品,你赶快再生产
	ir->repoNotFull.notify_all();
	lock.unlock();
	return item;
}

void ProduceTask(ItemRepository *ir)
{
	cout << "start to produce item!" << endl;
	for (int i = 0; i <= ITEMTOPRODUCE_COUNT; ++i)
	{
		ProduceItem(ir, i);
	}
	cout << "produce end!" << endl;
}

void ConsumeTask(ItemRepository *ir)
{
	bool isExit = false;
	cout << "thread [" << this_thread::get_id() << "start to consume!" << endl;
	while (true)
	{
		//每个线程阻塞自己一秒,否则其他线程有可能抢占不到锁而变成一个线程单消费
		this_thread::sleep_for(chrono::seconds(1));
		std::unique_lock<std::mutex> lock(ir->consumeCounterMutex);
		if (ir->consumeCounter <= ITEMTOPRODUCE_COUNT)
		{
			int item = ConsumeItem(ir);
			cout <<"thread [" << this_thread::get_id()  << "] is consuming " << item << "th item!" << endl;
			++ir->consumeCounter;
		}
		else 
		{
			isExit = true;
		}	
		if (isExit)
		{
			lock.unlock();
			break;
		}
		lock.unlock();
	}
	cout << "thread [" << this_thread::get_id() << "] consume end, cool!" << endl;
}

int main()
{
	ItemRepository gItemRepository;
	InitRepository(&gItemRepository);
	std::thread producer(ProduceTask, &gItemRepository);
	std::thread consumerOne(ConsumeTask, &gItemRepository);
	std::thread consumerTwo(ConsumeTask, &gItemRepository);
	std::thread consumerThree(ConsumeTask, &gItemRepository);
	std::thread consumerFour(ConsumeTask, &gItemRepository);
	producer.join();
	consumerOne.join();
	consumerTwo.join();
	consumerThree.join();
	consumerFour.join();
	getchar();
	return EXIT_SUCCESS;
}

多个生产者和多个消费者

#include <iostream>
#include <mutex>
#include <condition_variable>
#include <Windows.h>

using namespace std;

const int ITEMREPOSITORY_MAXSIZE = 10;
const int ITEMTOPRODUCE_COUNT = 100;

//使用环形队列
//生产者计数器和锁也可以放仓库外
struct ItemRepository
{
	int itemBuffer[ITEMREPOSITORY_MAXSIZE];
	size_t readPosition;
	size_t writePosition;
	int produceCounter;//生产者计数器
	int consumeCounter;//消费者计数器
	std::mutex mtx; //仓库锁
	std::mutex produceCounterMutex;//生产者计数锁
	std::mutex consumeCounterMutex;//消费者计数锁
	std::condition_variable repoNotFull; //仓库满时条件变量
	std::condition_variable repoNotEmpty; //仓库空时条件变量
};

void InitRepository(ItemRepository *ir)
{
	ir->readPosition = 0;
	ir->writePosition = 0;
	ir->produceCounter = 0;
	ir->consumeCounter = 0;
}

void ProduceItem(ItemRepository *ir, int item)
{
	std::unique_lock<std::mutex > lock(ir->mtx);
	//当仓库满时,阻塞自己,等待消费者消费
	while ((ir->writePosition + 1) % ITEMREPOSITORY_MAXSIZE == ir->readPosition)
	{
		cout << "Productor is waiting an empty slot..." << endl;
		ir->repoNotFull.wait(lock);
	}
	//有空位,往仓库放入产品
	ir->itemBuffer[ir->writePosition] = item;
	++ir->writePosition;
	//如果写入位置超出环形队列大小上限,移动到开始位置
	if (ir->writePosition >= ITEMREPOSITORY_MAXSIZE)
	{
		ir->writePosition = 0;
	}
	//通知消费者仓库不为空,快来消费
	ir->repoNotEmpty.notify_all();
	lock.unlock();
}

int ConsumeItem(ItemRepository *ir)
{
	std::unique_lock<mutex> lock(ir->mtx);
	//如果仓库为空,阻塞自己,等待生产者放入产品
	while (ir->readPosition == ir->writePosition)
	{
		cout << "repo is empty, consume is waiting a item..." << endl;
		ir->repoNotEmpty.wait(lock);
	}
	//仓库不为空,开始消费产品
	int item = ir->itemBuffer[ir->readPosition];
	++ir->readPosition;
	if (ir->readPosition >= ITEMREPOSITORY_MAXSIZE)
	{
		ir->readPosition = 0;
	}
	//通知生产者,我消耗了产品,你赶快再生产
	ir->repoNotFull.notify_all();
	lock.unlock();
	return item;
}

void ProduceTask(ItemRepository *ir)
{
	bool isExit = false;
	cout << "thread [" << this_thread::get_id() << "] start to produce item!" << endl;
	while (true)
	{
		//每个线程阻塞自己一秒,否则其他线程有可能抢占不到锁而变成单生产者
		this_thread::sleep_for(chrono::seconds(1));
		std::unique_lock<std::mutex> lock(ir->produceCounterMutex);
		if (ir->produceCounter < ITEMTOPRODUCE_COUNT)
		{
			++ir->produceCounter;
			ProduceItem(ir, ir->produceCounter);
			cout << "thread [" << this_thread::get_id() << "] has produced " << ir->produceCounter << "th item!" << endl;
		}
		else
		{
			isExit = true;
		}
		if (isExit)
		{
			lock.unlock();
			break;
		}
		lock.unlock();

	}
	cout << "thread [" << this_thread::get_id() << "] produce end!" << endl;
}

void ConsumeTask(ItemRepository *ir)
{
	bool isExit = false;
	cout << "thread [" << this_thread::get_id() << "] start to consume!" << endl;
	while (true)
	{
		//每个线程阻塞自己一秒,否则其他线程有可能抢占不到锁而变成一个线程单消费
		this_thread::sleep_for(chrono::seconds(1));
		std::unique_lock<std::mutex> lock(ir->consumeCounterMutex);
		if (ir->consumeCounter < ITEMTOPRODUCE_COUNT)
		{
			int item = ConsumeItem(ir);
			cout <<"thread [" << this_thread::get_id()  << "] is consuming " << item << "th item!" << endl;
			++ir->consumeCounter;
		}
		else 
		{
			isExit = true;
		}	
		if (isExit)
		{
			lock.unlock();
			break;
		}
		lock.unlock();
	}
	cout << "thread [" << this_thread::get_id() << "] consume end, cool!" << endl;
}

int main()
{
	ItemRepository gItemRepository;
	InitRepository(&gItemRepository);
	std::thread producerOne(ProduceTask, &gItemRepository);
	std::thread producerTwo(ProduceTask, &gItemRepository);
	std::thread consumerOne(ConsumeTask, &gItemRepository);
	std::thread consumerTwo(ConsumeTask, &gItemRepository);
	std::thread consumerThree(ConsumeTask, &gItemRepository);
	producerOne.join();
	producerTwo.join();
	consumerOne.join();
	consumerTwo.join();
	consumerThree.join();
	getchar();
	return EXIT_SUCCESS;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值