1、使用背景
假设有N个数据采集线程负责采集数据,有1个入库线程负责往数据库写数据,由于采集线程和入库线程是异步的,所以中间需要一个缓存区来作为采集线程和入库线程之间通信的桥梁,所以引入了循环队列。
2、N:1型场景
假设有N个采集线程,1个入库线程,架构图如下:
注意:
(1)由于采集线程入队时,操作的是队尾,有N个线程同时操作队尾,所以需要对这N个采集线程上锁(任何时刻只有一个采集线程在入队操作)
(2)而入库线程只有一个,同时呢,入库线程操作的是对头,和采集线程互不干涉,所以入库线程在入库时不需要上锁
3、循环队列代码实现
#ifndef __CQUEUE_H__
#define __CQUEUE_H__
#include <iostream>
using namespace std;
template <class T>
class CCircleQueue
{
public:
CCircleQueue(int size)
{
data_ = new T[size] ;
if(data_)
{
size_ = size;
head_ = 0;
tail_ = 0;
}
else
{
size_ = 0;
head_ = 0;
tail_ = 0;
}
}
~CCircleQueue()
{
delete []data_;
data_ = 0;
}
int size()
{
if(head_ == tail_)//队列为空
return 0;
else if(tail_>head_)
return tail_-head_;
else
return (size_-head_+tail_) ;
}
int space()
{
return size_ - size() - 1;//少使用一个元素
}
void empty()
{
head_ = 0;
tail_ = 0;
}
int pop_front_n(T* data_buf, int buf_size)
{
int n = size();
if(n==0)
{
cout << "The queue is empty." <<endl;
return 0;
}
if(n > buf_size)
n = buf_size ;
for(int i=0; i<n; i++)
{
data_buf[i] = data_[head_];
head_ = ((head_+1)%size_);
}
return n;
}
int push_back_n(T* data_buf, int buf_size)
{
int n = space();
if(n==0)
{
cout << "The queue is full." <<endl;
return 0;
}
if(n > buf_size)
n = buf_size ;
for(int i=0; i<n; i++)
{
data_[tail_] = data_buf[i];
tail_ = ((tail_+1)%size_);
}
return n ;
}
bool push_back(T& val)
{
if(space() > 0 )
{
data_[tail_] = val ;
tail_ = ((tail_+1)%size_);
return true;
}
else{
cout << "The queue is full." << endl;
return false ;
}
}
private:
int size_;
int head_;
int tail_;
T* data_ ;
};
#endif