C++解决方法:多线程同步经典案例之生产者消费者问题
导读:收集整理的这篇文章主要介绍了C++解决方法:多线程同步经典案例之生产者消费者问题,觉得挺不错的,现在分享给大家,也给大家做个参考。抄自维基百科 :生产者消费者问题(英语:PRoducer-consumer problem),也称有限缓冲问题...
收集整理的这篇文章主要介绍了C++解决方法:多线程同步经典案例之生产者消费者问题,觉得挺不错的,现在分享给大家,也给大家做个参考。抄自维基百科 :生产者消费者问题(英语:PRoducer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了共享固定大小缓冲区的两个线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。
本文用一个ITemRepository类表示产品仓库,其中包含一个数组和两个坐标表示的环形队列、一个std::mutex成员、用来保证每次只被一个线程读写操作 (为了保证打印出来的消息是一行一行的,在它空闲的时候也借用的这个互斥量╮(╯▽╰)╭)、两个std::condition_VARiable表示队列不满和不空的状态,进而保证生产的时候不满,消耗的时候不空。
#pragma once#include chrono> //std::chrono#include mutex> //std::mutex,std::unique_lock,std::lock_Guard#include thread> //std::thread#include condition_variable> //std::condition_variable#include iostream> //std::cout,std::endl#include map> //std::mapnamespace MyProducerToConsumer { static const int gRepositorySize = 10; //total size of the repository static const int gItemNum = 97; //number of products to produce std::mutex produce_mtx, consume_mtx; //mutex for all the producer thread or consumer thread std::mapstd::thread::id, int> threadPErformance; //records of every thread's producing/consuming number struct ItemRepository { //repository class int m_ItemBuffer[gRepositorySize]; //Repository itself (as a circular queue) int m_ProducePos; //rear position of circular queue int m_ConsumePos; //head position of circular queue std::mutex m_mtx; //mutex for operating the repository std::condition_variable m_RepoUnfull; //indicating that this repository is unfull(then producers can produce items) std::condition_variable m_RepoUnempty; //indicating that this repository is unempty(then consumers can produce items) } gItemRepo; void Produceitem(ItemRepository *ir, int item) { std::unique_lock std::mutex> ulk(ir-> m_mtx); while ((ir-> m_ProducePos + 1) % gRepositorySize == ir-> m_ConsumePos) { //full(spare one slot for indicating) std::cout "Reposity is full. Waiting for consumers..." std::endl; ir-> m_RepoUnfull.wait(ulk); //unlocking ulk and waiting for unfull condition } //when unfull ir-> m_ItemBuffer[ir-> m_ProducePos++] = item; //procude and shift std::cout "Item No." item " produced successfully by " std::this_thread::get_id()"!" std::endl; threadPerformance[std::this_thread::get_id()]++; if (ir-> m_ProducePos == gRepositorySize)//loop ir-> m_ProducePos = 0; ir-> m_RepoUnempty.notify_all(); //item produced, so it's unempty; notify all consumers } int ConsumeItem(ItemRepository *ir) { std::unique_lockstd::mutex> ulk(ir-> m_mtx); while (ir-> m_ConsumePos == ir-> m_ProducePos) { //empty std::cout "Repository is empty.Waiting for producing..." std::endl; ir-> m_RepoUnempty.wait(ulk); } int item = ir-> m_ItemBuffer[ir-> m_ConsumePos++]; std::cout "Item No." item " consumed successfully by " std::this_thread::get_id()"!" std::endl; threadPerformance[std::this_thread::get_id()]++; if (ir-> m_ConsumePos == gRepositorySize) ir-> m_ConsumePos = 0; ir-> m_RepoUnfull.notify_all(); //item consumed, so it's unempty; notify all consumers return item; } void ProducerThread() { static int produced = 0; //static variable to indicate the number of produced items while (1) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); //sleep long enough in case it runs too fast for other threads to procude std::lock_guardstd::mutex> lck(produce_mtx); //auto unlock when break produced++; if (produced > gItemNum)break; gItemRepo.m_mtx.lock(); std::cout "Producing item No." produced "..." std::endl; gItemRepo.m_mtx.unlock(); ProduceItem(& gItemRepo, produced); } gItemRepo.m_mtx.lock(); std::cout "Producer thread " std::this_thread::get_id() " exited." std::endl; gItemRepo.m_mtx.unlock(); } void ConsumerThread() { static int consumed = 0; while (1) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::lock_guardstd::mutex> lck(consume_mtx); consumed++; if (consumed > gItemNum)break; gItemRepo.m_mtx.lock(); std::cout "Consuming item available..." std::endl; gItemRepo.m_mtx.unlock(); ConsumeItem(& gItemRepo); } gItemRepo.m_mtx.lock(); std::cout "Consumer thread " std::this_thread::get_id() " exited." std::endl; gItemRepo.m_mtx.unlock(); } void InitItemRepository(ItemRepository* ir) { ir-> m_ConsumePos = 0; ir-> m_ProducePos = 0; } void Run() { InitItemRepository(& gItemRepo); std::thread thdConsume[11]; std::thread thdProduce[11]; for (auto& t : thdConsume)t = std::thread(ConsumerThread); for (auto& t : thdProduce)t = std::thread(ProducerThread); for (auto& t : thdConsume)t.join(); for (auto& t : thdProduce)t.join(); for (auto& iter : threadPerformance)cout iter.First ":" iter.second endl; } }
相关文章:
关于java生产者与消费者的实例详解
java多线程之并发协作生产者消费者设计模式
以上就是C++解决方法:多线程同步经典案例之生产者消费者问题的详细内容,更多请关注其它相关文章!
声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!
若转载请注明出处: C++解决方法:多线程同步经典案例之生产者消费者问题
本文地址: https://pptw.com/jishu/593144.html