[C++ 2011 多线程系列二]多线程阻塞队列


/*
cblockingdeque.h
描述了阻塞队列的实现
*/

#ifndef _H_CBLOCKINGDEQUE_INCLUDE_
#define _H_CBLOCKINGDEQUE_INCLUDE_

#include <mutex>
#include <deque>
#include <condition_variable>

//阻塞式队列
template <typename T> class CBlockingDeque
{
public: 
 CBlockingDeque(int maxcount);
 //放入队列元素
 bool push_back(T &t);
 //弹出队列元素
 bool pop_front(T &t,int milliseconds);
 //获取队列元素数目
 size_t size();
private:
 //最大容量
 const size_t m_maxcount;
 //互斥锁
 std::mutex m_mutex;
 //std::unique_lock<std::mutex> lock(m,std::defer_lock);
 //条件变量
 std::condition_variable m_cond;
 //标准队列
 std::deque<T> m_deque;
};

template <typename T> CBlockingDeque<T>::CBlockingDeque(int maxcount):m_maxcount(maxcount)
{
 //
}

template <typename T> bool CBlockingDeque<T>::push_back(T &t)
{
 bool result = false;  
 std::unique_lock<std::mutex> lock(m_mutex);
 if(m_deque.size() < this->m_maxcount)
 {
  m_deque.push_back(t);   
  m_cond.notify_all();
  result = true;  
 }  
 return result;
}

template <typename T> bool CBlockingDeque<T>::pop_front(T &t,int milliseconds)
{
 bool result = false;
 if(milliseconds <= 0)
 {
  return result;
 }
 
 std::unique_lock<std::mutex> lock(m_mutex);
 if(m_deque.empty())
 {
  std::cv_status::cv_status cv = std::cv_status::no_timeout;
  cv = m_cond.wait_for(lock,std::chrono::milliseconds(milliseconds));
  if(std::cv_status::no_timeout == cv)
  {
   //
  }
 }

 if(!m_deque.empty())
 {
  t = m_deque.front();
  m_deque.pop_front();
  result = true;
 }

 return result;
}

//
template <typename T> size_t CBlockingDeque<T>::size()
{
 std::lock_guard<std::mutex> m(this->m_mutex);
 return m_deque.size();
}

#endif

 

 

 


/*
blockingdeque.cpp
演示了阻塞队列的调用
*/

#include <iostream>
#include <sstream>
#include <functional>
#include <thread>
#include <mutex>
#include <future>
#include <math.h>
using namespace std;

#include "cblockingdeque.h"

class CTestBlockingDeque
{
public:
 void push_back(CBlockingDeque<std::string> *bd,size_t total)
 {  
  size_t k = 0;
  for(size_t i = 0;i < total;++i)
  {
   std::stringstream str;
   str<<"ITEM"<<i;
   std::string s = str.str();
   if(bd->push_back(s))
   {
    k++;
   }
  }
  std::cout<<std::this_thread::get_id()<<" push success total:"<<k<<endl;
 }

 int pop_front(CBlockingDeque<std::string> *bd,int milliseconds)
 {
  int count = 0;
  int failcount = 0;
  while(failcount < 1)
  {
   std::string s = "";
   if(bd->pop_front(s,milliseconds))
   {
    count++;  
   }
   else
   {
    failcount++;
   }
  }
  std::cout<<std::this_thread::get_id()<<" pop_front fail total:"<<failcount<<endl;
  return count;
 } 


 static void start_test()
 {
  const int totalitem = 100000;
  CBlockingDeque<std::string> bd(totalitem);
  CTestBlockingDeque test_bd;

  //构造3个插入线程
  auto fnarg = std::bind(&CTestBlockingDeque::push_back,&test_bd,&bd,std::placeholders::_1);
  std::thread push_task_1(fnarg,50000);
  std::thread push_task_2(fnarg,40000);
  std::thread push_task_3(fnarg,30000);

  //std::this_thread::sleep_for(std::chrono::milliseconds(100));

  //构造2个输出线程
  auto fnarg_1 = std::bind(&CTestBlockingDeque::pop_front,&test_bd,&bd,500);
  auto fnarg_2 = std::bind(&CTestBlockingDeque::pop_front,&test_bd,&bd,100);
  std::packaged_task<int (CBlockingDeque<std::string> *,int)> pos_packaged_1(fnarg_1);
  std::packaged_task<int (CBlockingDeque<std::string> *,int)> pos_packaged_2(fnarg_2);
  std::future<int> future_1 = pos_packaged_1.get_future();
  std::future<int> future_2 = pos_packaged_2.get_future();
  std::thread pop_task_1(std::move(pos_packaged_1),nullptr,0);
  std::thread pop_task_2(std::move(pos_packaged_2),nullptr,0);

  std::thread::id id_1 = pop_task_1.get_id();
  std::thread::id id_2 = pop_task_2.get_id();

  //等待线程都正常退出
  push_task_1.join();
  push_task_2.join();
  push_task_3.join();
  pop_task_1.join();
  pop_task_2.join();

  int total_1 = future_1.get();
  int total_2 = future_2.get();

  std::cout<<id_1<<" pop total:"<<total_1<<endl;
  std::cout<<id_2<<" pop total:"<<total_2<<endl;
  std::cout<<"pop total:"<<total_1 + total_2<<endl;
 }
};

int main(int argc, char* argv[])
{
 //using namespace std::placeholders; //for _1, _2, _3...
 
 CTestBlockingDeque::start_test();
 system("pause");
 return 0;
}

 

 

 

VS2012 Update2 下运行结果:

75288 pop_front fail total:1
74000 push success total:30000
73720 push success total:40000
74216 push success total:50000
75228 pop_front fail total:1
75288 pop total:3837
75228 pop total:116163
pop total:120000

 

你可能感兴趣的:(多线程,C++,2011)