c++ 无锁队列的简单实现

简介: c++ 无锁队列的简单实现

无锁队列的基本介绍


一个关于无锁队列的多线程读写代码示例。在这里,我提供一个简单的示例来说明这个问题。


在使用无锁队列时,需要注意以下几点:


使用原子操作来实现对队列的读写操作,以避免多线程同时访问同一数据导致的竞争条件问题。


当队列为空或已满时,需要使用特殊的标记来表示队列的状态。


使用链表来实现的无锁队列


下面是一个使用无锁队列的多线程读写代码示例:

#include <atomic>
#include <thread>
#include <iostream>
template <typename T>
class LockFreeQueue
{
public:
    LockFreeQueue() : m_head(new Node), m_tail(m_head.load()) {}
    ~LockFreeQueue()
    {
        while (Node* const old_head = m_head)
        {
            m_head = old_head->next;
            delete old_head;
        }
    }
    void enqueue(T value)
    {
        Node* const new_node = new Node(value);
        Node* old_tail = m_tail.exchange(new_node);
        old_tail->next = new_node;
    }
    bool dequeue(T& value)
    {
        Node* old_head = m_head;
        Node* new_head;
        do
        {
            if (old_head->next == nullptr)
            {
                return false;
            }
            new_head = old_head->next;
        } while (!m_head.compare_exchange_weak(old_head, new_head));
        value = new_head->value;
        delete old_head;
        return true;
    }
private:
    struct Node
    {
        T value;
        Node* next;
        Node() : next(nullptr) {}
        Node(T value) : value(value), next(nullptr) {}
    };
    std::atomic<Node*> m_head;
    std::atomic<Node*> m_tail;
};
int main()
{
    LockFreeQueue<int> queue;
    std::thread t1([&queue]()
    {
        for (int i = 0; i < 10; ++i)
        {
            queue.enqueue(i);
        }
    });
    std::thread t2([&queue]()
    {
        int value = 0;
        while (value < 9)
        {
            if (queue.dequeue(value))
            {
                std::cout << "Dequeued value: " << value << std::endl;
            }
        }
    });
    t1.join();
    t2.join();
    return 0;
}


这段代码实现了一个无锁队列,其中enqueue()函数用于向队列中添加元素,dequeue()函数用于从队列中取出元素。在这个示例中,我们使用了C++11中的std::atomic来实现原子操作,以确保多线程访问时的线程安全。同时,我们使用了compare_exchange_weak()函数来确保多线程环境下的原子操作。


以环形队列实现无锁队列


#include <atomic>
template <typename T>
class LockFreeQueue {
public:
    LockFreeQueue(size_t capacity = 1024) : m_capacity(capacity) {
        m_data = new T[m_capacity];
        m_head.store(0, std::memory_order_relaxed);
        m_tail.store(0, std::memory_order_relaxed);
    }
    ~LockFreeQueue() {
        delete[] m_data;
        m_data = nullptr;
    }
    bool push(const T& item) {
        size_t tail = m_tail.load(std::memory_order_relaxed);
        size_t head = m_head.load(std::memory_order_acquire);
        size_t count = tail - head;
        if (count >= m_capacity - 1) {
            return false;
        }
        m_data[tail % m_capacity] = item;
        m_tail.store(tail + 1, std::memory_order_release);
        return true;
    }
    bool pop(T& item) {
        size_t head = m_head.load(std::memory_order_relaxed);
        size_t tail = m_tail.load(std::memory_order_acquire);
        size_t count = tail - head;
        if (count == 0) {
            return false;
        }
        item = m_data[head % m_capacity];
        m_head.store(head + 1, std::memory_order_release);
        return true;
    }
private:
    T* m_data;
    size_t m_capacity;
    std::atomic<size_t> m_head;
    std::atomic<size_t> m_tail;
};


这个队列是一个环形队列,使用了两个原子变量 m_headm_tail 分别表示队列头和队列尾,通过利用原子操作保证线程安全,实现了无锁的操作。同时,使用了 memory_order 来保证数据的可见性和原子性。

相关文章
|
6月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
302 77
|
5月前
|
存储 算法 C++
【c++丨STL】priority_queue(优先级队列)的使用与模拟实现
本文介绍了STL中的容器适配器`priority_queue`(优先级队列)。`priority_queue`根据严格的弱排序标准设计,确保其第一个元素始终是最大元素。它底层使用堆结构实现,支持大堆和小堆,默认为大堆。常用操作包括构造函数、`empty`、`size`、`top`、`push`、`pop`和`swap`等。我们还模拟实现了`priority_queue`,通过仿函数控制堆的类型,并调用封装容器的接口实现功能。最后,感谢大家的支持与关注。
218 1
|
6月前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
223 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
6月前
|
存储 C语言 C++
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
118 9
|
6月前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
166 7
|
8月前
|
缓存 安全 C++
C++无锁队列:解锁多线程编程新境界
【10月更文挑战第27天】
481 7
|
8月前
|
消息中间件 存储 安全
|
8月前
|
存储 设计模式 C++
【C++】优先级队列(容器适配器)
本文介绍了C++ STL中的线性容器及其适配器,包括栈、队列和优先队列的设计与实现。详细解析了`deque`的特点和存储结构,以及如何利用`deque`实现栈、队列和优先队列。通过自定义命名空间和类模板,展示了如何模拟实现这些容器适配器,重点讲解了优先队列的内部机制,如堆的构建与维护方法。
122 0
|
11月前
|
存储 设计模式 算法
【C++】deque以及优先级队列
【C++】deque以及优先级队列
|
5月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。