多线程设计模式:Producer-Consumer生产者-消费者模式的C++

  我们这里介绍的Producer-Consumer生产者-消费者模式是多线程设计模式中很著名的一个设计模式。说到生产者消费者问题,大部分人都不会陌生,OS课的经典问题,并且其本身就是一个计算机编程中常见的问题。对于它的应用,可以举出无数的例子,小到一个多线程程序对队列的共享互斥操作,大到目前流行的中间件产品,诸如BEA的BMQ(BEA Message Queue),IBM的MQ Serious等中间件就是将生产者消费者问题应用通用化体系化的结果。

实际上,生产者消费者模式跟我们之前的多线程设计模式Guarded Suspension模式的PPL和C++实例非常相似。在计算机科学中,我们将生产者消费者问题描述为:

一群生产者在生产消息,并将此消息提供给消费者去消费。它们中间设了具有N个缓存区的缓冲池,生产者每次可将生产的消息放入一个缓存区内,消费者每次可将一个缓存区内的消息拿出来消费。但这个过程有两个条件:

  (1)任何一方操作一个缓冲区时不能有其它同时对该缓冲区进行操作;

  (2)只有当缓冲区还有空余,生产者才能生产,只有当缓冲区至少有一个产品,消费者才能从中取出来消费。

  这里两个条件分别对应了互斥和同步。

  大家可以发现,生产者消费者模式就是在Guarded Suspension模式的基础上作了更多的限制,Guarded Suspension模式不限制缓冲区的容量,随时都可以向缓冲区添加新的消息,但是生产者消费者模式对缓冲区的容量作了限制,当缓冲区满了之后,就不能了在向其中添加消息了。简单来说,Producer Consumer模式就像是加上了双重防护与等待的Guarded Suspension模式,而它的两个防护与等待的条件洽好相反,我们将Guarded Suspension模式修改一下,就可以实现生产者消费者模式。

// ProducerConsumer.cpp : 定义控制台应用程序的入口点。

using namespace Concurrency;
using namespace std;
class Request
{
public:
  Request(unsigned int nID)
  : m_nID(nID)
  {

  }
  unsigned int getID()
  {
    return m_nID;
  }
private:
  unsigned int m_nID;
};

// 请求队列
// 客户端将请求添加进入这个队列
// 服务器从这个队列中获取来自客户端的请求进行处理
class RequestQueue
{
public:
  // 获取请求,如果当前请求队列为空,则进行等待
  Request getRequest()
  {
    bool bWait = true;
    while( bWait )
    {
      // 如果缓冲区中没有请求,则进行等待,
      wait(500);
      cs.lock();
      bWait = m_Queue.size() > 0 ? false : true;
      cs.unlock();
    }
    cs.lock();
    Request req = m_Queue.front();
    m_Queue.pop();
    wait(1000);
    cout<<"GET:"< cs.unlock();
    return req;
  }
// 将请求加入请求队列中
void setRequest(Request req)
{
  bool bWait = false;
  do
  {
    // 限制缓冲区的大小,这是生产者消费者模式比Guarded Suspension模式多添加的一个保护
    cs.lock();
    bWait = m_Queue.size() < 5 ? false : true;
    if(bWait)
    {
      cout<<"Wait..."< wait(500);
    }
    cs.unlock();
  }
  while(bWait);
  cs.lock();
  m_Queue.push(req);
  cout<<"SET:"< cs.unlock();
}
private:
  critical_section cs; // 为了保护队列访问的临界区
  queue m_Queue;
};

int _tmain(int argc, _TCHAR* argv[])
{
  srand((int)time(NULL));

  RequestQueue queue;
  // 模拟多个客户端的请求,也就是生产者线程
  auto request = make_task( [&]()
  {
    int nCount = 0;
    while(nCount<20)
    {
      wait(rand()%10);
      queue.setRequest(Request(nCount));
      ++nCount;
    }
  });
  // 模拟客户端的处理,也就是消费者线程
  auto process = make_task( [&]()
  {
    while(true)
    queue.getRequest();
  });

  // 执行请求和处理的线程
  task_group tg;
  tg.run(process);
  tg.run_and_wait(request);

  return 0;
}  

  在这个例子中,生产者线程不断产生请求,向RequestQueue中添加请求,当RequestQueue中的请求大于5时,就等待,不再向其中添加请求,而消费者线程不断从RequestQueue中获得请求进行处理,当queue中没有请求时,它就进行等待。生产者消费者模式简单而有效,被得到广泛应用。

时间: 2024-11-09 04:11:57

多线程设计模式:Producer-Consumer生产者-消费者模式的C++的相关文章

java中多线程通信实例:生产者消费者模式

线程间的通信: 其实就是多个线程再操作同一个资源,但是操作的动作不同   当某个线程进入synchronized块后,共享数据的状态不一定满足该线程的需要,需要其他线程改变共享数据的状态后才能运行,而由于当时线程对共享资源时独占的,它必须解除对共享资源的锁定的状态,通知其他线程可以使用该共享资源. Java中的 wait(),notify(),notifyAll()可以实现线程间的通信. 生产者--消费者问题是典型的线程同步和通信问题 /** * 生产者和消费者问题,生产者生成出产品,消费者去购

java 多线程并发系列之 生产者消费者模式的两种实现

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题.该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度. 为什么要使用生产者和消费者模式 在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程.在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据.同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者.为了解决这种生产消费能力不均衡的问题,所以便有了生产者和消费者模式. 什么是生

多线程之生产者消费者模式

最近在项目中需要使用使用多线程实现一种功能,和生产者消费者模式类似,因此,学习了下生产者消费者模式的多线程实现.在生产者消费者模式中,通常有两类线程, 即若干个生产者线程和若干个消费者线程.生产者线程负责提交用户请求,消费者线程则负责处理生产者提交的任务.生产者和消费者之间则通过共享内存缓冲区进行通信. 在这里我们选择BlockingQueue做为共享内存缓冲区. 首先,我们构建生产者生产的,和消费者需要处理的数据PCData,即相关任务数据. public class PCData { pri

11.9-全栈Java笔记: 线程并发协作(生产者/消费者模式)

多线程环境下,我们经常需要多个线程的并发和协作.这个时候,就需要了解一个重要的多线程并发协作模型"生产者消费者模式". 什么是生产者? 生产者指的是负责生产数据的模块(这里模块可能是:方法.对象.线程.进程). 什么是消费者? 消费者指的是负责处理数据的模块(这里模块可能是:方法.对象.线程.进程). 什么是缓冲区? 消费者不能直接使用生产者的数据,它们之间有个"缓冲区".生产者将生产好的数据放入"缓冲区",消费者从"缓冲区"

Java的设计模式(7)— 生产者-消费者模式

生产者-消费者模式是一个经典的多线程设计模式,它为多线程间的协作提供了良好的解决方案.这个模式中,通常有两类线程,即若干个生产者线程和若干个消费者线程.生产者线程负责提交用户请求,消费者线程则负责具体处理生产者提交的任务.生产者和消费者之间通过共享内存缓存区进行通信,这样就避免了生产者和消费者直接通信,从而将生产者和消费者解耦.不管是生产高于消费,还是消费高于生产,缓存区的存在可以确保系统的正常运行.这个模式有以下几种角色: 生产者:用于提交用户的请求,提取用户任务,装入内存缓冲区. 消费者:在

多线程:生产者/消费者模式

生产者/消费者模式 实际上,很多后台服务程序并发控制的基本原理都可以归纳为生产者/消费者模式. 生产者消费问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,消费者则可以从仓库中取走产品.解决生产者/消费者问题的方法可以分为两类: 采用某种机制保护生产者和消费者之间的同步: 生产者和消费者之间建立一个管道. 第一种方式有较高的效率,并且易于实现,代码的可控制性较好,属于常用的模式. 第二种管道缓冲不易控制,被传输数据对象不易于封装,实用性不强. 同步问题的核心在于:如何保证

java 多线程 22 :生产者/消费者模式 进阶 利用await()/signal()实现

java多线程15 :wait()和notify() 的生产者/消费者模式 在这一章已经实现了  wait/notify 生产消费模型 利用await()/signal()实现生产者和消费者模型 一样,先定义一个缓冲区: public class ValueObject { public static String value = ""; } 换种写法,生产和消费方法放在一个类里面: public class ThreadDomain41 extends ReentrantLock {

JAVA多线程之生产者消费者模式

一.什么是生产者消费者模式? 生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力. 二.为什么要使用生产者和消费者模式 在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程.在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产

Java多线程-----实现生产者消费者模式的几种方式

   1 生产者消费者模式概述 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理, 直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力.这个阻塞队列就是用来给生产者和消费者解耦的. 在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程.在多线程开发当中,如果生产者处理速度很快,而消费者处理速度