循环队列模板
介绍
实现
例程
介绍
- 循环队列在实际编程过程中使用频率较高,其实现方法也有多种,基于锁、条件变量、原子操作等,也有开源的无锁队列项目,总而言之可以找到许多阅读学习资料。
- 此文实现时将数据类型泛化,旨在实现支持基本读写、可异步读写、简捷可用的接口。
- 使用二维指针、原子操作,模板泛化等实现此循环队列模板。
实现
- LoopQueueTemplate.hpp文件内容如下:
#ifndef LOOPQUEUETEMPLATE_HPP
#define LOOPQUEUETEMPLATE_HPP
#include <atomic>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <map>
template <typename T> class LoopQueueTemplate {
public:
LoopQueueTemplate(int32_t row, int32_t col) : m_data(nullptr) {
try {
assert(row > 0 && col > 0);
m_row = row;
m_col = col;
m_data = new T *[row];
for (int i = 0; i < m_row; ++i) {
m_data[i] = new T[col];
m_map[i] = 0;
}
m_readPos = 0;
m_writePos = 0;
m_currentPos = 0;
} catch (...) {
throw "new loop queue failed";
}
}
~LoopQueueTemplate() {
for (int i = 0; i < m_row; ++i) {
if (m_data[i] != nullptr)
delete[] m_data[i];
}
if (m_data)
delete[] m_data;
m_map.clear();
}
void Reset() {
m_readPos = 0;
m_writePos = 0;
m_currentPos = 0;
for (int i = 0; i < m_row; ++i)
m_map[i] = 0;
}
bool IsOverLoop() const { return m_currentPos > m_row; }
// 写入数据(方式1)
bool Write(const T *data, uint32_t len) {
if (m_data == nullptr || data == nullptr || len == 0 || len > m_col)
return false;
if (m_writePos >= m_row)
m_writePos = 0;
memcpy(m_data[m_writePos], data, sizeof(T) * len);
m_map[m_writePos] = len;
m_writePos++;
m_currentPos++;
return true;
}
// 读取数据(方式1)
bool Read(T *data, uint32_t &realLen /*in & out*/) {
if (m_data == nullptr || data == nullptr || m_currentPos < 1)
return false;
if (realLen > m_map[m_readPos])
realLen = m_map[m_readPos];
if (m_readPos >= m_row)
m_readPos = 0;
memcpy(data, m_data[m_readPos], sizeof(T) * realLen);
m_readPos++;
m_currentPos--;
return true;
}
// 读取数据(方式2)
T *GetReadPtr(uint32_t *realLen /*out*/) {
if (m_data == nullptr || m_currentPos < 1)
return nullptr;
if (m_readPos >= m_row)
m_readPos = 0;
*realLen = m_map[m_readPos];
return m_data[m_readPos];
}
bool ReadFinish() {
if (m_currentPos < 1)
return false;
m_readPos++;
m_currentPos--;
return true;
}
// 写入数据(方式2)
T *GetWritePtr(uint32_t *maxWriteLen /*out*/) {
*maxWriteLen = m_col;
if (m_data == nullptr)
return nullptr;
if (m_writePos >= m_row)
m_writePos = 0;
return m_data[m_writePos];
}
bool WriteFinish(uint32_t len) {
if (len > m_col)
return false;
m_map[m_writePos] = len;
m_writePos++;
m_currentPos++;
return true;
}
private:
T **m_data;
std::atomic_uint32_t m_readPos; // or std::atomic<uint32_t>
std::atomic_uint32_t m_writePos;
std::atomic_int32_t m_currentPos;
int32_t m_row;
int32_t m_col;
std::map<uint32_t, uint32_t> m_map;
};
#endif // LOOPQUEUETEMPLATE_H
- 基于如上模板,封装char类型容器LoopQueueChar如下:
// LoopQueue.h
#ifndef LOOPQUEUE_H
#define LOOPQUEUE_H
#include <cstdint>
template <typename T> class LoopQueueTemplate;
class LoopQueueChar {
public:
LoopQueueChar(uint32_t row, uint32_t col);
void Reset();
bool IsOverLoop() const;
bool Read(char *data, uint32_t &len /*in & out*/);
bool Write(const char *data, uint32_t len);
char *GetReadPtr(uint32_t *realLen /*out*/);
bool ReadFinish();
char *GetWritePtr(uint32_t *maxWriteLen /*out*/);
bool WriteFinish(uint32_t len);
private:
LoopQueueTemplate<char> *m_queue;
};
#endif // LOOPQUEUE_H
// LoopQueue.cpp
#include "LoopQueue.h"
#include "LoopQueueTemplate.hpp"
LoopQueueChar::LoopQueueChar(uint32_t row, uint32_t col)
: m_queue(new LoopQueueTemplate<char>(row, col)) {}
void LoopQueueChar::Reset() { m_queue->Reset(); }
bool LoopQueueChar::IsOverLoop() const { return m_queue->IsOverLoop(); }
bool LoopQueueChar::Read(char *data, uint32_t &len) {
return m_queue->Read(data, len);
}
bool LoopQueueChar::Write(const char *data, uint32_t len) {
return m_queue->Write(data, len);
}
char *LoopQueueChar::GetReadPtr(uint32_t *realLen) {
return m_queue->GetReadPtr(realLen);
}
bool LoopQueueChar::ReadFinish() { return m_queue->ReadFinish(); }
char *LoopQueueChar::GetWritePtr(uint32_t *maxWriteLen) {
return m_queue->GetWritePtr(maxWriteLen);
}
bool LoopQueueChar::WriteFinish(uint32_t len) {
return m_queue->WriteFinish(len);
}
例程
- 使用LoopQueueChar例程如下:
#include <iostream>
#include "LoopQueue.h"
#include <thread>
#include <chrono>
#include <atomic>
int main() {
LoopQueueChar que(10, 64);
std::atomic_bool stop = false;
std::thread t1([&que, &stop] {
int index = 0;
uint32_t maxLen = 0;
std::this_thread::sleep_for(std::chrono::seconds(1));
while (index++ < 2000) {
std::string str = "write string: " + std::to_string(index);
char *ptr = que.GetWritePtr(&maxLen);
if (ptr == nullptr || maxLen < 1) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
memcpy(ptr, str.c_str(), str.size());
que.WriteFinish(str.size());
}
std::this_thread::sleep_for(std::chrono::seconds(1));
stop = true;
});
std::thread t2([&que, &stop] {
uint32_t realLen = 0;
char buf[64] = {0};
int recvCount = 0;
while (!stop) {
char *ptr = que.GetReadPtr(&realLen);
if (ptr == nullptr || realLen < 1) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
memcpy(buf, ptr, realLen);
que.ReadFinish();
recvCount++;
}
std::cout << "stop state: " << std::string(buf)
<< ", recv count: " << recvCount << std::endl;
});
if (t1.joinable())
t1.join();
if (t2.joinable())
t2.join();
return 0;
}
输出结果: stop state: write string: 2000, recv count: 2000
#include <iostream>
#include "LoopQueue.h"
#include <thread>
#include <chrono>
#include <atomic>
int main() {
LoopQueueChar que(10, 64);
std::atomic_bool stop = false;
std::thread t1([&que, &stop] {
int index = 0;
uint32_t maxLen = 0;
std::this_thread::sleep_for(std::chrono::seconds(1));
while (index++ < 20000) {
std::string str = "write string: " + std::to_string(index);
if (!que.Write(str.c_str(), str.size())) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
}
std::this_thread::sleep_for(std::chrono::seconds(1));
stop = true;
});
std::thread t2([&que, &stop] {
uint32_t realLen = 0;
char buf[64] = {0};
int recvCount = 0;
uint32_t len = sizeof(buf);
while (!stop) {
len = sizeof(buf);
if (!que.Read(buf, len)) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
recvCount++;
}
std::cout << "stop state: " << std::string(buf)
<< ", recv count: " << recvCount << std::endl;
});
if (t1.joinable())
t1.join();
if (t2.joinable())
t2.join();
return 0;
}
输出结果:stop state: write string: 20000, recv count: 20000