无锁队列实现(Michael Scott),伪代码与c++实现

news2024/12/25 10:18:01

一、Michael & Scoot 原版伪代码实现

structure pointer_t {ptr: pointer to node_t, count: unsigned integer}
  structure node_t {value: data type, next: pointer_t}
  structure queue_t {Head: pointer_t, Tail: pointer_t}
  
  initialize(Q: pointer to queue_t)
     node = new_node()		// Allocate a free node
     node->next.ptr = NULL	// Make it the only node in the linked list
     Q->Head.ptr = Q->Tail.ptr = node	// Both Head and Tail point to it
  
  enqueue(Q: pointer to queue_t, value: data type)
   E1:   node = new_node()	// Allocate a new node from the free list
   E2:   node->value = value	// Copy enqueued value into node
   E3:   node->next.ptr = NULL	// Set next pointer of node to NULL
   E4:   loop			// Keep trying until Enqueue is done
   E5:      tail = Q->Tail	// Read Tail.ptr and Tail.count together
   E6:      next = tail.ptr->next	// Read next ptr and count fields together
   E7:      if tail == Q->Tail	// Are tail and next consistent?
               // Was Tail pointing to the last node?
   E8:         if next.ptr == NULL
                  // Try to link node at the end of the linked list
   E9:            if CAS(&tail.ptr->next, next, <node, next.count+1>)
  E10:               break	// Enqueue is done.  Exit loop
  E11:            endif
  E12:         else		// Tail was not pointing to the last node
                  // Try to swing Tail to the next node
  E13:            CAS(&Q->Tail, tail, <next.ptr, tail.count+1>)
  E14:         endif
  E15:      endif
  E16:   endloop
         // Enqueue is done.  Try to swing Tail to the inserted node
  E17:   CAS(&Q->Tail, tail, <node, tail.count+1>)
  
  dequeue(Q: pointer to queue_t, pvalue: pointer to data type): boolean
   D1:   loop			     // Keep trying until Dequeue is done
   D2:      head = Q->Head	     // Read Head
   D3:      tail = Q->Tail	     // Read Tail
   D4:      next = head.ptr->next    // Read Head.ptr->next
   D5:      if head == Q->Head	     // Are head, tail, and next consistent?
   D6:         if head.ptr == tail.ptr // Is queue empty or Tail falling behind?
   D7:            if next.ptr == NULL  // Is queue empty?
   D8:               return FALSE      // Queue is empty, couldn't dequeue
   D9:            endif
                  // Tail is falling behind.  Try to advance it
  D10:            CAS(&Q->Tail, tail, <next.ptr, tail.count+1>)
  D11:         else		     // No need to deal with Tail
                  // Read value before CAS
                  // Otherwise, another dequeue might free the next node
  D12:            *pvalue = next.ptr->value
                  // Try to swing Head to the next node
  D13:            if CAS(&Q->Head, head, <next.ptr, head.count+1>)
  D14:               break             // Dequeue is done.  Exit loop
  D15:            endif
  D16:         endif
  D17:      endif
  D18:   endloop
  D19:   free(head.ptr)		     // It is safe now to free the old node
  D20:   return TRUE                   // Queue was not empty, dequeue succeeded

二、C++实现

c++的实现就直接看上述的伪代码跟着实现即可,这里的一些atomic操作也可以看我之前写的博客

template<typename T>
class LockFreeQueue {
private:
    // 队列结构
    struct Node {
        std::shared_ptr<T> data;
        std::atomic<Node*> next;

        Node() : next(nullptr) {};
    };

    std::atomic<Node*> head; // 头节点
    std::atomic<Node*> tail; // 尾节点
    Node* dummy; // 用于回收节点的哑节点

public:
    LockFreeQueue() {
        dummy = new Node();
        head.store(dummy);
        tail.store(dummy);
    }

    ~LockFreeQueue() {
        T output;
        while (dequeue(output)) {}
        delete dummy;
    }

    // 禁止拷贝构造和赋值
    LockFreeQueue(const LockFreeQueue&) = delete;
    LockFreeQueue& operator=(const LockFreeQueue&) = delete;

    void enqueue(const T& value) {
        std::shared_ptr<T> new_data(std::make_shared<T>(value)); // 创建数据
        Node* new_node = new Node();  // 创建新节点
        Node* old_tail;

        while (true) {
            old_tail = tail.load();
            Node* next = old_tail->next.load();

            if (old_tail == tail.load()) { // 此时保证tail还没有被其他线程改变
                if (next == nullptr) { // 此时保证tail是队列的最后一个节点
                    if (old_tail->next.compare_exchange_weak(next, new_node)) break; // 插入成功,这是一个原语,可以一次操作
                }
                else { // 说明tail落后了,推进tail指针
                    tail.compare_exchange_weak(old_tail, next);
                }
            }
        }

        old_tail->data = new_data;
        tail.compare_exchange_weak(old_tail, new_node);
    }

    bool dequeue(T& value) {
        Node* old_head;

        while (true) {
            old_head = head.load();  // 获取当前头部节点
            Node* old_tail = tail.load();  // 获取当前尾部节点
            Node* next = old_head->next.load();

            if (old_head == head.load()) { // 确保head没有被改变
                if (old_head == old_tail) { // 队列为空,或者tail落后
                    if (next == nullptr) { // 队列为空
                        return false;
                    }
                    tail.compare_exchange_weak(old_tail, next);
                } else {
                    // 从队列中移除head,并且读取其值
                    if (next->data) {
                        value = *(next->data);
                        if (head.compare_exchange_weak(old_head, next)) break; // 清除head节点,退出循环
                    }
                }
            }
        }

        delete old_head;
        return true;
    }
};

三、测试

测试代码如下:

int main() {
    LockFreeQueue<int> queue;

    std::thread t1([&queue](){
        for(int i=0; i<100; i++) {
            queue.enqueue(i);
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
    });

    std::thread t2([&queue](){
        for(int i=100; i<200; i++) {
            queue.enqueue(i);
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
    });

    std::thread t3([&queue]() {
        while (true) {
            int i = 0;
            if (queue.dequeue(i)) {
                std::cout << "t3:" << i << std::endl;
            }
        }
    });

    std::thread t4([&queue]() {
        while (true) {
            int i = 0;
            if (queue.dequeue(i)) {
                std::cout << "t4:" << i << std::endl;
            }
        }
    });

    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

image-20241014161649144

可以看到,多线程下可以顺利的插入与找到数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2216440.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

薪资管理系统原型PC端+移动端 Axure原型 交互设计 Axure实战项目

薪资管理系统原型PC端移动端 Salary Management System Prototype 薪资管理系统原型图是一种以图形化方式展示系统界面和功能交互的设计图形。该原型图旨在呈现薪资管理系统的整体架构、界面布局和用户交互流程&#xff0c;为开发团队和利益相关者提供一个清晰而具体的概念。…

CSS 实战录: 双栏、四等分、不等间距、自适应...

引言 一个当初困扰我许久的设计稿还原问题, 故在此做个简单记录!! 设计稿布局大概如下图所示 整体分为左右两部分同时划分了模块 A B C DA B C 之间的间距为 24px, C D 之间的间距为 64px整体宽度 100% 自适应铺满, 并且 A B C D 宽度保持一致 那么问题来了, 假设给出下面 DO…

Python | Leetcode Python题解之第473题火柴拼正方形

题目&#xff1a; 题解&#xff1a; class Solution:def makesquare(self, matchsticks: List[int]) -> bool:totalLen sum(matchsticks)if totalLen % 4:return FalsetLen totalLen // 4dp [-1] * (1 << len(matchsticks))dp[0] 0for s in range(1, len(dp)):fo…

【市场解读】传统到端到端的智驾分水岭已至

参考文献&#xff1a;平安证券《汽车行业深度报告&#xff1a;智驾分水岭已至》 关键词学习 端到端智驾系统end to end “端到端”智驾是一种新的智能驾驶技术&#xff0c;不再依赖于传统的感知原件&#xff0c;而是通过算法、AI、模型架构数据迭代来实现自主学习和思考能力…

MySQL数据库从入门到精通 第1讲 基本概念

MySQL数据库从入门到精通 第1讲 基本概念 小可爱们&#xff0c;接下来我们要学习的知识是数据库相关的知识&#xff0c;从本贴开始&#xff0c;从0基础带大家入门到精通&#xff0c;要加油哦~ 1 前言 1.1 为什么要学习数据库&#xff1f; 那我们首先要搞清楚第一个问题&…

深入了解EasyNVR及EasyNVS,EasyNVR连接到EasyNVS当显示授权超时如何解决?又因为什么原因?

我们先来了解NVR批量管理软件/平台EasyNVR&#xff0c;它深耕市场多年&#xff0c;为用户提供多种协议&#xff0c;兼容多种厂商设备&#xff0c;包括但不限于支持海康&#xff0c;大华&#xff0c;宇视&#xff0c;萤石&#xff0c;天地伟业&#xff0c;华为设备。 NVR录像机…

华为FreeBuds 6i戴久了会耳朵胀痛吗?该怎么办?

华为FreeBuds 6i戴久了&#xff0c;会有耳朵胀痛的感觉吗&#xff1f;其实可能是没选对适合自己的耳塞&#xff0c;给你们分享几个佩戴更舒服的方法&#xff0c;一起来看看~ 首先和大家说说为什么华为FreeBuds 6i戴久了不舒服&#xff0c;一方面是耳塞尺寸不合适&#xff0c;另…

Visual Studio 2022 配置 Boost 库

一、使用预编译版本 尽量不要使用预编译版本&#xff0c;因为可能构建的不完全&#xff0c;还得重新构建&#xff0c;不如一步到位 1. 下载预编译的 Boost 库 下载&#xff1a;Boost C Libraries - Browse /boost-binaries at SourceForge.net 2. 选择 msvc 版本&#xff0…

如何将一张图片分成四份,四宫格?图片分割的8种简单方法

如何将一张图片分成四份&#xff0c;四宫格&#xff1f;在日常的图像处理任务中&#xff0c;我们时常会遇到各种特殊的需求。今天&#xff0c;我就遇到了一项颇具挑战性的任务——在特殊情况下&#xff0c;需要将一张图片精确地分成四份&#xff0c;形成一个标准的四宫格。这项…

SQL第15课——插入数据

介绍利用SQL的insert语句将数据插入表中。 15.1 数据插入 select是最常用的语句&#xff0c;但是还有3个常用的SQL语句&#xff0c;第一个就是insert&#xff0c; insert&#xff1a;用来将行插入&#xff08;或添加&#xff09;到数据库表。插入的3中方式&#xff1a; 1. …

光伏仿真系统在光伏项目开发中有哪些应用场景?

光伏仿真系统在光伏项目开发中的应用场景广泛&#xff0c;涵盖了从项目规划、设计优化到运维管理的全过程。 一、项目规划与选址 1、气象模拟与评估 光伏仿真系统能够基于历史气象数据和先进的预测模型&#xff0c;模拟不同地理位置、不同季节和时间段的光照强度、温度、湿度…

网络层及ip报头

★★★★★默写&#xff1a; A类&#xff1a;0~127 B类&#xff1a;128~191 C类&#xff1a;192~223 A类私网&#xff1a;10.0.0 - 10.255.255.255 B类私网&#xff1a;172.16.0.0 - 172.31.255.255 C类私网&#xff1a;19.168.0.0 - 192.168.255.255 特殊&#xff1a; 0.0.0…

百度智能云新一代云原生产品加速 AI 原生应用落地

本文整理自百度云智峰会 2024 —— 云原生论坛的同名演讲。 今天为大家分享在过去的一年里&#xff0c;围绕 AI 原生的大背景下&#xff0c;百度智能云在基础公有云的计算、存储、网络以及云原生等产品和技术方面所做出的核心工作。 随着大模型所带来的 AI 技术的代际演化&…

用Spring AI 做智能客服,基于私有知识库和RAG技术

Java智能客服系统运用RAG技术提升答疑精准度 基于Spring ai 的 RAG&#xff08;检索增强生成&#xff09;技术&#xff0c;Java智能客服系统能够利用私有知识库中的信息提供更准确的答疑服务。 它的核心思路是&#xff1a; 首先&#xff0c;将客服QA以Word形式导入到系统中&…

python配合yolo分类模型开发分类软件

上一篇文章写了yolo的分类模型的训练&#xff0c;写篇文章基于yolo分类模型开发分类软件。开发环境:pycharm&#xff0c;PySide6 6.6.1 &#xff0c;PySide6-Addons 6.6.1&#xff0c;PySide6-Essentials 6.6.1&#xff0c;torch 2.3.1cu121&#xff0c;torchaudio 2.3.1cu121&…

能源领域下暖通行业现状-研究

基于AI大语言模型的暖通行业能源管理系统构建研究 一、能源管理中的突出问题 1. **能源消耗监测不准确** 现有的监测系统在获取设备实时能耗数据方面存在精度不足的问题&#xff0c;难以准确反映能源的实际使用情况。这使得节能决策缺乏可靠的数据支持&#xff0c;无法精准定位…

Hbase安装及使用

安装 官网下载:Apache HBase – Apache HBase Downloads 启动 先启动zookeeper及hadoop 关系&#xff1a;HBase通过Zookeeper来做master的高可用、RegionServer的监控、元数据的入口以及集群配置的维护等工作。 再启动start-hbase.sh(/opt/module/hbase-2.2.3/bin&#xf…

大华智能云网关注册管理平台 SQL注入漏洞复现(CNVD-2024-38747)

0x01 产品简介 大华智能云网关注册管理平台是一款专为解决社会面视频资源接入问题而设计的高效、便捷的管理工具,平台凭借其高效接入、灵活部署、安全保障、兼容性和便捷管理等特点,成为了解决社会面视频资源接入问题的优选方案。该平台不仅提高了联网效率,降低了联网成本,…

【计算机网络】详解IP协议网段划分路由转发子网掩码网络号

一、IP功能 IP可以实现主机定位和路由选择&#xff0c;提供一种能力&#xff0c;将数据可靠地从A点跨网络送到B点。数据先根据目的IP在局域网之间进行转发&#xff0c;再在局域网内进行内网转发。 二、IP协议报头 4 位版本号(version)&#xff1a;指定 IP 协议的版本&#xff…

如何轻松使用pip安装Git仓库中的私有Python模块(使用pip和Git仓库发布和安装私有Python模块)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 Git模块 📒📝 Git仓库要求🔖 项目目录结构🔖 文件说明📝 编写setup.py📝 配置MANIFEST.in📝 推送代码到Git仓库📝 使用pip安装模块🔖 使用用户名和密码🔖 使用Personal Access Token (PAT)🔖 示例📝 更…