/*********************************************************************************
- FileName: ListQueue.hpp
- Author: pipilu
- Version: 1.0
- Date: 20181108
- Description: 一个基于list的队列缓冲区,采用模板方便使用者传入自定义数据,pop数据的
模式设计成阻塞超时方式,使用者无需在外层sleep
- History:
1.Date: 20181108
Author: pipilu
Modification: Original release
**********************************************************************************/
#ifndef CLISTQUEUE_HPP_
#define CLISTQUEUE_HPP_
#include <list>
#include <mutex>
#include <chrono>
#include <memory>
#ifndef UINT32_MAX
#define UINT32_MAX 0xFFFFFFFF
#endif
///
//本队列使用了模板,方便使用者传入自定义数据,使用者也可以使用这里注释的结构体
//typedef struct _DataPackage
//{
// std::shared_ptr<unsigned char> spData;
// unsigned int len;
//
// _DataPackage() : len(0) {}
// _DataPackage(const unsigned char* pData, unsigned int dataLen)
// : len(dataLen)
// {
// spData.reset(new unsigned char[dataLen]);
// memcpy(spData.get(), pData, dataLen);
// }
//}DataPackage;
///
template<typename T>
class CListQueue
{
public:
CListQueue() : m_okey( false ) {}
~CListQueue()
{
fini();
}
bool init(uint32_t size = UINT32_MAX)
{
if (isOkey())
return true;
m_okey = true;
m_maxSize = size;
return true;
}
void fini()
{
if (!isOkey())
return;
m_okey = false;
m_cond.notify_all();
clear();
}
bool isOkey()
{
return m_okey;
}
uint16_t size()
{
std::unique_lock<std::mutex> lock( m_mutex );
return m_queue.size();
}
/**
* @brief 增加数据到队列尾
*
* @param[in] t 数据
* @param[in] bDiscard 当队列个数达上限的情况下,本次传进的数据包处理策略 false:删除头数据后压栈 true:丢弃本次数据包并返回false
*
* @return true:成功 false:失败
*/
bool push( const T & t , bool bDiscard = false) //bDiscard参数是否丢弃本次传进来的包
{
std::unique_lock<std::mutex> lock( m_mutex );
if ( m_queue.size() < m_maxSize )
{
m_queue.push_back( t );
}
else
{
if (bDiscard)
{
std::cout << "Pkg count is over max, this packet will be discarded!!!" << std::endl;
return false;
}
m_queue.pop_front();
m_queue.push_back(t);
}
m_cond.notify_all();
return true;
}
/**
* @brief 从队列头取出数据
*
* @param[out] t 数据
* @param[in] waitTime 当队列为空时,本次pop的阻塞等待时间( 本队列模式设计为阻塞模式 )
*
* @return true:成功 false:失败
*/
bool pop( T & t, const uint32_t waitTime = UINT32_MAX )
{
std::unique_lock<std::mutex> lock( m_mutex );
if ( !m_okey )
{
return false;
}
if ( waitTime == UINT32_MAX )
{
while ( m_queue.empty() && m_okey ) //有可能唤醒一次但仍没数据,所以需要 whlie继续等待
{
m_cond.wait( lock );
}
}
else
{
std::cv_status cv_ret = std::cv_status::no_timeout;
while ( m_queue.empty() && m_okey && (std::cv_status::no_timeout == cv_ret) ) //有可能唤醒一次但仍没数据,所以需要 whlie继续等待
{
cv_ret = m_cond.wait_for(lock, std::chrono::milliseconds(waitTime));
}
if (std::cv_status::timeout == cv_ret)
{
std::cout << "Getting packets times out!!!" << std::endl;
return false;
}
}
if (!m_okey)
{
return false;
}
t = std::move(m_queue.front()); // 取出队首元素,返回队首元素值,并进行右值引用
m_queue.pop_front();
return true;
}
void popFront()
{
std::unique_lock<std::mutex> lock( m_mutex );
if (!m_queue.empty())
m_queue.pop_front();
}
void clear()
{
std::unique_lock<std::mutex> lock( m_mutex );
m_queue.clear();
}
private:
std::mutex m_mutex;
std::condition_variable m_cond;
volatile bool m_okey;
uint32_t m_maxSize;
std::list<T> m_queue;
};
#endif // CLISTQUEUE_HPP_
一个很实用的的缓冲区队列
最新推荐文章于 2022-10-10 15:22:11 发布