生产者消费者设计模式.docx

上传人:b****7 文档编号:10152423 上传时间:2023-02-08 格式:DOCX 页数:18 大小:17.18KB
下载 相关 举报
生产者消费者设计模式.docx_第1页
第1页 / 共18页
生产者消费者设计模式.docx_第2页
第2页 / 共18页
生产者消费者设计模式.docx_第3页
第3页 / 共18页
生产者消费者设计模式.docx_第4页
第4页 / 共18页
生产者消费者设计模式.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

生产者消费者设计模式.docx

《生产者消费者设计模式.docx》由会员分享,可在线阅读,更多相关《生产者消费者设计模式.docx(18页珍藏版)》请在冰豆网上搜索。

生产者消费者设计模式.docx

生产者消费者设计模式

基于C++11实现生产者消费者设计模式

本文将综合运用C++11中的新的基础设施(主要是多线程、锁、条件变量)来阐述一个经典问题——生产者消费者模式,并给出完整的解决方案。

生产者消费者问题是多线程并发中一个非常经典的问题,相信学过操作系统课程的同学都清楚这个问题的根源。

本文将就四种情况分析并介绍生产者和消费者问题,它们分别是:

单生产者-单消费者模式,单生产者-多消费者模式,多生产者-单消费者模式,多生产者-多消费者模式,我会给出四种情况下的C++11并发解决方案,如果文中出现了错误或者你对代码有异议,欢迎交流。

1单生产者-单消费者模式

顾名思义,单生产者-单消费者模式中只有一个生产者和一个消费者,生产者不停地往产品库中放入产品,消费者则从产品库中取走产品,产品库容积有限制,只能容纳一定数目的产品,如果生产者生产产品的速度过快,则需要等待消费者取走产品之后,产品库不为空才能继续往产品库中放置新的产品,相反,如果消费者取走产品的速度过快,则可能面临产品库中没有产品可使用的情况,此时需要等待生产者放入一个产品后,消费者才能继续工作。

C++11实现单生产者单消费者模式的代码如下:

#include

#include

#include

#include

#include

#include

staticconstintkItemRepositorySize=10;//Itembuffersize.

staticconstintkItemsToProduce=1000;//Howmanyitemsweplantoproduce.

structItemRepository{

intitem_buffer[kItemRepositorySize];//产品缓冲区,配合read_position和write_position模式环形队列.

size_tread_position;//消费者读取产品位置.

size_twrite_position;//生产者写入产品位置.

std:

:

mutexmtx;//互斥量,保护产品缓冲区

std:

:

condition_variablerepo_not_full;//条件变量,指示产品缓冲区不为满.

std:

:

condition_variablerepo_not_empty;//条件变量,指示产品缓冲区不为空.

}gItemRepository;//产品库全局变量,生产者和消费者操作该变量.

typedefstructItemRepositoryItemRepository;

 

voidProduceItem(ItemRepository*ir,intitem)

{

std:

:

unique_lock

:

mutex>lock(ir->mtx);

while(((ir->write_position+1)%kItemRepositorySize)

==ir->read_position){//itembufferisfull,justwaithere.

std:

:

cout<<"Produceriswaitingforanemptyslot...\n";

(ir->repo_not_full).wait(lock);//生产者等待"产品库缓冲区不为满"这一条件发生.

}

(ir->item_buffer)[ir->write_position]=item;//写入产品.

(ir->write_position)++;//写入位置后移.

if(ir->write_position==kItemRepositorySize)//写入位置若是在队列最后则重新设置为初始位置.

ir->write_position=0;

(ir->repo_not_empty).notify_all();//通知消费者产品库不为空.

lock.unlock();//解锁.

}

intConsumeItem(ItemRepository*ir)

{

intdata;

std:

:

unique_lock

:

mutex>lock(ir->mtx);

//itembufferisempty,justwaithere.

while(ir->write_position==ir->read_position){

std:

:

cout<<"Consumeriswaitingforitems...\n";

(ir->repo_not_empty).wait(lock);//消费者等待"产品库缓冲区不为空"这一条件发生.

}

data=(ir->item_buffer)[ir->read_position];//读取某一产品

(ir->read_position)++;//读取位置后移

if(ir->read_position>=kItemRepositorySize)//读取位置若移到最后,则重新置位.

ir->read_position=0;

(ir->repo_not_full).notify_all();//通知消费者产品库不为满.

lock.unlock();//解锁.

returndata;//返回产品.

}

 

voidProducerTask()//生产者任务

{

for(inti=1;i<=kItemsToProduce;++i){

//sleep

(1);

std:

:

cout<<"Producethe"<

:

endl;

ProduceItem(&gItemRepository,i);//循环生产kItemsToProduce个产品.

}

}

voidConsumerTask()//消费者任务

{

staticintcnt=0;

while

(1){

sleep

(1);

intitem=ConsumeItem(&gItemRepository);//消费一个产品.

std:

:

cout<<"Consumethe"<

:

endl;

if(++cnt==kItemsToProduce)break;//如果产品消费个数为kItemsToProduce,则退出.

}

}

voidInitItemRepository(ItemRepository*ir)

{

ir->write_position=0;//初始化产品写入位置.

ir->read_position=0;//初始化产品读取位置.

}

intmain()

{

InitItemRepository(&gItemRepository);

std:

:

threadproducer(ProducerTask);//创建生产者线程.

std:

:

threadconsumer(ConsumerTask);//创建消费之线程.

producer.join();

consumer.join();

}

2单生产者-多消费者模式

与单生产者和单消费者模式不同的是,单生产者-多消费者模式中可以允许多个消费者同时从产品库中取走产品。

所以除了保护产品库在多个读写线程下互斥之外,还需要维护消费者取走产品的计数器,代码如下:

#include

#include

#include

#include

#include

#include

staticconstintkItemRepositorySize=4;//Itembuffersize.

staticconstintkItemsToProduce=10;//Howmanyitemsweplantoproduce.

structItemRepository{

intitem_buffer[kItemRepositorySize];

size_tread_position;

size_twrite_position;

size_titem_counter;

std:

:

mutexmtx;

std:

:

mutexitem_counter_mtx;

std:

:

condition_variablerepo_not_full;

std:

:

condition_variablerepo_not_empty;

}gItemRepository;

typedefstructItemRepositoryItemRepository;

 

voidProduceItem(ItemRepository*ir,intitem)

{

std:

:

unique_lock

:

mutex>lock(ir->mtx);

while(((ir->write_position+1)%kItemRepositorySize)

==ir->read_position){//itembufferisfull,justwaithere.

std:

:

cout<<"Produceriswaitingforanemptyslot...\n";

(ir->repo_not_full).wait(lock);

}

(ir->item_buffer)[ir->write_position]=item;

(ir->write_position)++;

if(ir->write_position==kItemRepositorySize)

ir->write_position=0;

(ir->repo_not_empty).notify_all();

lock.unlock();

}

intConsumeItem(ItemRepository*ir)

{

intdata;

std:

:

unique_lock

:

mutex>lock(ir->mtx);

//itembufferisempty,justwaithere.

while(ir->write_position==ir->read_position){

std:

:

cout<<"Consumeriswaitingforitems...\n";

(ir->repo_not_empty).wait(lock);

}

data=(ir->item_buffer)[ir->read_position];

(ir->read_position)++;

if(ir->read_position>=kItemRepositorySize)

ir->read_position=0;

(ir->repo_not_full).notify_all();

lock.unlock();

returndata;

}

 

voidProducerTask()

{

for(inti=1;i<=kItemsToProduce;++i){

//sleep

(1);

std:

:

cout<<"Producerthread"<

:

this_thread:

:

get_id()

<<"producingthe"<

:

endl;

ProduceItem(&gItemRepository,i);

}

std:

:

cout<<"Producerthread"<

:

this_thread:

:

get_id()

<<"isexiting..."<

:

endl;

}

voidConsumerTask()

{

boolready_to_exit=false;

while

(1){

sleep

(1);

std:

:

unique_lock

:

mutex>lock(gItemRepository.item_counter_mtx);

if(gItemRepository.item_counter

intitem=ConsumeItem(&gItemRepository);

++(gItemRepository.item_counter);

std:

:

cout<<"Consumerthread"<

:

this_thread:

:

get_id()

<<"isconsumingthe"<

:

endl;

}elseready_to_exit=true;

lock.unlock();

if(ready_to_exit==true)break;

}

std:

:

cout<<"Consumerthread"<

:

this_thread:

:

get_id()

<<"isexiting..."<

:

endl;

}

voidInitItemRepository(ItemRepository*ir)

{

ir->write_position=0;

ir->read_position=0;

ir->item_counter=0;

}

intmain()

{

InitItemRepository(&gItemRepository);

std:

:

threadproducer(ProducerTask);

std:

:

threadconsumer1(ConsumerTask);

std:

:

threadconsumer2(ConsumerTask);

std:

:

threadconsumer3(ConsumerTask);

std:

:

threadconsumer4(ConsumerTask);

producer.join();

consumer1.join();

consumer2.join();

consumer3.join();

consumer4.join();

}

3多生产者-单消费者模式

与单生产者和单消费者模式不同的是,多生产者-单消费者模式中可以允许多个生产者同时向产品库中放入产品。

所以除了保护产品库在多个读写线程下互斥之外,还需要维护生产者放入产品的计数器,代码如下:

#include

#include

#include

#include

#include

#include

staticconstintkItemRepositorySize=4;//Itembuffersize.

staticconstintkItemsToProduce=10;//Howmanyitemsweplantoproduce.

structItemRepository{

intitem_buffer[kItemRepositorySize];

size_tread_position;

size_twrite_position;

size_titem_counter;

std:

:

mutexmtx;

std:

:

mutexitem_counter_mtx;

std:

:

condition_variablerepo_not_full;

std:

:

condition_variablerepo_not_empty;

}gItemRepository;

typedefstructItemRepositoryItemRepository;

 

voidProduceItem(ItemRepository*ir,intitem)

{

std:

:

unique_lock

:

mutex>lock(ir->mtx);

while(((ir->write_position+1)%kItemRepositorySize)

==ir->read_position){//itembufferisfull,justwaithere.

std:

:

cout<<"Produceriswaitingforanemptyslot...\n";

(ir->repo_not_full).wait(lock);

}

(ir->item_buffer)[ir->write_position]=item;

(ir->write_position)++;

if(ir->write_position==kItemRepositorySize)

ir->write_position=0;

(ir->repo_not_empty).notify_all();

lock.unlock();

}

intConsumeItem(ItemRepository*ir)

{

intdata;

std:

:

unique_lock

:

mutex>lock(ir->mtx);

//itembufferisempty,justwaithere.

while(ir->write_position==ir->read_position){

std:

:

cout<<"Consumeriswaitingforitems...\n";

(ir->repo_not_empty).wait(lock);

}

data=(ir->item_buffer)[ir->read_position];

(ir->read_position)++;

if(ir->read_position>=kItemRepositorySize)

ir->read_position=0;

(ir->repo_not_full).notify_all();

lock.unlock();

returndata;

}

voidProducerTask()

{

boolready_to_exit=false;

while

(1){

sleep

(1);

std:

:

unique_lock

:

mutex>lock(gItemRepository.item_counter_mtx);

if(gItemRepository.item_counter

++(gItemRepository.item_counter);

ProduceItem(&gItemRepository,gItemRepository.item_counter);

std:

:

cout<<"Producerthread"<

:

this_thread:

:

get_id()

<<"isproducingthe"<

<<"^thitem"<

:

endl;

}elseready_to_exit=true;

lock.unlock();

if(ready_to_exit==true)break;

}

std:

:

cout<<"Producerthread"<

:

this_thread:

:

get_id()

<<"isexiting..."<

:

endl;

}

voidConsumerTask()

{

staticintitem_consumed=0;

while

(1){

sleep

(1);

++item_consumed;

if(item_consumed<=kItemsToProduce){

intitem=ConsumeItem(&gItemRepository);

std:

:

cout<<"Consumerthread"<

:

this_thread:

:

get_id()

<<"isconsumingthe"<

:

endl;

}elsebreak;

}

std:

:

cout<<"Consumerthread"<

:

this_thread:

:

get_id()

<<"isexiting..."<

:

endl;

}

voidInitItemRepository(ItemRepository*ir)

{

ir->write_position=0;

ir->read_position=0;

ir->item_counter=0;

}

intmain()

{

InitItemRepository(&gItemRepository);

std:

:

threadproducer1(ProducerTask);

std:

:

threadproducer2(ProducerTask);

std:

:

threadproducer3(ProducerTask);

std:

:

threadproducer4(ProducerTask);

std:

:

threadconsumer(ConsumerTask);

producer1.join();

producer2.join();

producer3.join();

producer4.join();

consumer.join();

}

4多生产者-多消费者模式

该模式可以说是前面两种模式的综合,程序需要维护两个计数器,分别是生产者已生产产品的数目和消费者已取走产品的数目。

另外也需要保护产品库在多个生产者和多个消费者互斥地访问。

代码如下:

#include

#include

#include

#include

#in

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 表格模板 > 合同协议

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1