基于c++11无锁循环队列

循环队列模板

介绍

实现

例程

介绍

  • 循环队列在实际编程过程中使用频率较高,其实现方法也有多种,基于锁、条件变量、原子操作等,也有开源的无锁队列项目,总而言之可以找到许多阅读学习资料。
  • 此文实现时将数据类型泛化,旨在实现支持基本读写、可异步读写、简捷可用的接口。
  • 使用二维指针、原子操作,模板泛化等实现此循环队列模板。

实现

  • 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

起始

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值