readerwriterqueue C++单生产者,单消费者无锁队列

1、readerwriterqueue C++单生产者,单消费者无锁队列,它只支持两个线程用例,一个用于生产,一个用于消费

github地址:https://github.com/cameron314/readerwriterqueue

2、优点

快速

兼容C++11标准

就像 std::queue 一样,你不需要为元素分配内存

在连续块中预先分配内存

提供一种try_enqueue保证永不分配内存的方法(队列以初始容量开始)

还提供了enqueue一种可以根据需要动态增加队列大小的方法

等等

3、使用

atomicops.h文件和readerwriterqueue.h文件放在项目中去,使用的时候需要#include "readerwriterqueue.h"就可以了

具体的几个函数介绍如下

enqeue:入队

try_enqueue:入队,如果队列空间不够返回false

try_dequeue:出队,如果队列为空返回false

size_approx():当前队列的大小

max_capacity():当前队列的最大容量,会动态变化的

pop():从队列中删除最前面的一个元素

另外还有一个阻塞版本的(BlockReaderWriterQueue),阻塞版本接口和非阻塞版本(ReaderWriterQueue)接口基本一样,并新增了wait_dequeue()和wait_dequeue_timed()两个函数

具体使用例子如下

#include <iostream>
#include "readerwriterqueue.h"
using namespace moodycamel;

int main(void){
    // 预先分配内存
    ReaderWriterQueue<int> q(10);
    // 数据进队
    for(int i=1;i<=11;++i){
        q.enqeue(i);
    }
    // 打印大小
    std::cout << q.size_approx() << std::endl;
    
    // 出队
    // try_dequeue成功返回true,失败返回false,表示没有拿到数据
    int val;
    while(q.size_approx()){
        q.try_dequeue(val);
        std::cout << "val:" << val << std::endl;
    }
    if(!q.try_dequeue(val)){
        std::cout << "no value" << std::endl;
    }
    
    return 0;
}

 接下来会使用两个线程,一个线程往队列中写数据,一个线程从队列中读数据

#include <chrono>
#include <iostream>
#include <thread>

#include "readerwriterqueue.h"

using namespace moodycamel;
int main(void) {
    // 两个线程,一个线程写数据一个线程读数据
    // 预先分配内存
    ReaderWriterQueue<int> q(10);
    std::cout << q.max_capacity() << std::endl;

    int val = 1;
    std::thread writer([&]() {
        while (true) {
            q.enqueue(val++);
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
        }
    });

    std::thread reader([&]() {
        int tmp;
        while (true) {
            if (!q.try_dequeue(tmp)) {
                continue;
            }
            std::cout << tmp << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
        }
    });

    writer.join();
    reader.join();

    return 0;
}

 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于无锁队列生产者消费者模型可以使用C++11中的atomic和memory_order来实现。以下是一个简的实现示例: ``` #include <atomic> #include <memory> template<typename T> class LockFreeQueue { public: LockFreeQueue() { Node* node = new Node; tail_.store(node, std::memory_order_relaxed); head_.store(node, std::memory_order_relaxed); } ~LockFreeQueue() { T value; while (pop(value)); Node* node = head_.load(std::memory_order_relaxed); delete node; } void push(const T& value) { Node* node = new Node(value); Node* prev_tail = tail_.exchange(node, std::memory_order_acq_rel); prev_tail->next.store(node, std::memory_order_release); } bool pop(T& value) { Node* head = head_.load(std::memory_order_relaxed); Node* next = head->next.load(std::memory_order_acquire); if (!next) { return false; } value = next->value; head_.store(next, std::memory_order_release); delete head; return true; } private: struct Node { Node() : next(nullptr) {} Node(const T& value) : value(value), next(nullptr) {} T value; std::atomic<Node*> next; }; std::atomic<Node*> head_; std::atomic<Node*> tail_; }; ``` 在构造函数中,我们创建了一个节点,并将头指针和尾指针都指向该节点。在push操作中,我们创建一个新节点,并使用std::atomic::exchange函数原子地将尾指针指向新节点,并返回原来的尾节点。然后将原来的尾节点的next指针指向新节点。在pop操作中,我们先取出头节点的next指针,如果为nullptr,则说明队列为空,返回false。否则,我们将头指针指向next节点,并返回next节点的值。最后,我们删除原来的头节点。 需要注意的是,在push操作中,我们使用std::memory_order_acq_rel来保证对tail指针的读写操作都是原子的,并且保证任何其他线程在读取tail指针之前都已经完成了对前一个节点的更新操作。在pop操作中,我们使用std::memory_order_acquire来保证对next指针的读取是原子的,并且保证任何其他线程在更新next指针之前都已经完成了对头节点的更新操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值