无锁队列实现(Michael Scott),伪代码与c++实现
一、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 nodenode->next.ptr = NULL // Make it the only node in the linked listQ->Head.ptr = Q->Tail.ptr = node // Both Head and Tail point to itenqueue(Q: pointer to queue_t, value: data type)E1: node = new_node() // Allocate a new node from the free listE2: node->value = value // Copy enqueued value into nodeE3: node->next.ptr = NULL // Set next pointer of node to NULLE4: loop // Keep trying until Enqueue is doneE5: tail = Q->Tail // Read Tail.ptr and Tail.count togetherE6: next = tail.ptr->next // Read next ptr and count fields togetherE7: 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 listE9: if CAS(&tail.ptr->next, next, <node, next.count+1>)E10: break // Enqueue is done. Exit loopE11: endifE12: else // Tail was not pointing to the last node// Try to swing Tail to the next nodeE13: CAS(&Q->Tail, tail, <next.ptr, tail.count+1>)E14: endifE15: endifE16: endloop// Enqueue is done. Try to swing Tail to the inserted nodeE17: CAS(&Q->Tail, tail, <node, tail.count+1>)dequeue(Q: pointer to queue_t, pvalue: pointer to data type): booleanD1: loop // Keep trying until Dequeue is doneD2: head = Q->Head // Read HeadD3: tail = Q->Tail // Read TailD4: next = head.ptr->next // Read Head.ptr->nextD5: 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 dequeueD9: endif// Tail is falling behind. Try to advance itD10: 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 nodeD12: *pvalue = next.ptr->value// Try to swing Head to the next nodeD13: if CAS(&Q->Head, head, <next.ptr, head.count+1>)D14: break // Dequeue is done. Exit loopD15: endifD16: endifD17: endifD18: endloopD19: free(head.ptr) // It is safe now to free the old nodeD20: 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();
}

可以看到,多线程下可以顺利的插入与找到数据
相关文章:
无锁队列实现(Michael Scott),伪代码与c++实现
一、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_…...
猜数字小游戏
前言 猜数字游戏是一款经典且简单的互动游戏,常常用于提高逻辑思维能力和锻炼数学技巧。本文将深入探讨一段用 JavaScript 编写的猜数字游戏代码,帮助读者理解游戏的基本逻辑和实现方法。这段代码不仅适合初学者练习编程技巧,也是了解用户交…...
在Windows上搭建ChatTTS:从本地部署到远程AI音频生成全攻略
文章目录 前言1. 下载运行ChatTTS模型2. 安装Cpolar工具3. 实现公网访问4. 配置ChatTTS固定公网地址 前言 本篇文章主要介绍如何快速地在Windows系统电脑中本地部署ChatTTS开源文本转语音项目,并且我们还可以结合Cpolar内网穿透工具创建公网地址,随时随…...
如何用好 CloudFlare 的速率限制防御攻击
最近也不知道咋回事儿,群里好多站长都反映被CC 攻击了。有人说依旧是 PCDN 干的,但明月感觉不像,因为有几个站长被 CC 攻击都是各种动态请求(这里的动态请求指的是.php 文件的请求)。经常被攻击的站长们都知道,WordPress /Typecho 这类动态博客系统最怕的就是这种动态请求…...
Unity3D 立方体纹理与自制天空盒详解
立方体纹理和自制天空盒是游戏开发中常用的技术之一,可以为游戏增添更加丰富的视觉效果。在本文中,我们将详细介绍Unity3D中立方体纹理和自制天空盒的使用方法,并给出相应的代码实现。 对惹,这里有一个游戏开发交流小组ÿ…...
【工具】VSCODE下载,配置初次设置
打开 settings.json 文件,包含了 Visual Studio Code (VSCode) 中的各种用户配置。 {"files.associations": {"*.vue": "vue","*.wpy": "vue","*.wxml": "html","*.wxss": "…...
vue使用jquery的ajax,页面跳转
一、引入jquery依赖 打开终端更新npm npm install -g npm 更新完后引入输入npm install jquery 加载完后 在最外层的package.json文件中加入以下代码 配置好后导入jquery 设置变量用于接收服务器传输的数据 定义ajax申请数据 服务器的Controller层传输数据 (…...
基于微信小程序的社区二手交易系统的详细设计和实现(源码+lw+部署文档+讲解等)
项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念,提供了一套默认的配置,让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…...
D34【python 接口自动化学习】- python基础之输入输出与文件操作
day34 文件关闭 学习日期:20241011 学习目标:输入输出与文件操作﹣-46 常见常新:文件的关闭 学习笔记: 文件关闭的内部工作过程 close()函数 with语句 常用的打开关闭文件 # 文件关闭 # 方式…...
【Linux系列】set -euo pipefail 命令详解
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
【Python爬虫实战】正则:中文匹配与贪婪非贪婪模式详解
🌈个人主页:https://blog.csdn.net/2401_86688088?typeblog 🔥 系列专栏:https://blog.csdn.net/2401_86688088/category_12797772.html 目录 前言 一、匹配中文 (一)匹配单个中文字符 (二…...
保护数据安全:JS前端加密与PHP后端解密实战教程,让敏感信息更安全
保护数据安全:JS前端加密与PHP后端解密实战教程,让敏感信息更安全 在Web开发中,确保用户提交的敏感信息(如密码、手机号码等)的安全性是非常重要的。一种常见的做法是使用加密技术来保护这些数据,在传输过…...
72 分布式锁
72 分布式锁 什么是分布式锁 分布式锁 分布式 锁。那么分布式是指的什么呢?锁又是锁的谁呢?在业务开发中我们经常会听到分布式分布式的概念,分布式也很简单,通俗的来说就是你具有多个服务器,每个服务器上运行的程序…...
使用Windbg分析dump文件排查C++软件异常的一般步骤与要点分享
目录 1、概述 2、打开dump文件,查看发生异常的异常类型码 3、查看发生异常的那条汇编指令 3.1、汇编代码能最直接、最本真的反映出崩溃的原因 3.2、汇编指令中访问64KB小地址内存区,可能是访问了空指针 3.3、汇编指令中访问了很大的内核态的内存地…...
30 天 Python 3 学习计划
30 天 Python 3 学习计划 https://www.runoob.com/python3/python3-tutorial.html 1. Python3 基础语法 2. Python3 基本数据类型 3. Python3 数据类型转换 4. Python3 解释器 5. Python3 注释 6. Python3 运算符 7. Python3 数字(Number) 8. Python3 字符串 …...
【MATLAB实例】批量提取.csv数据并根据变量名筛选
【MATLAB实例】批量提取.csv数据并根据变量名筛选 准备:数据说明MATLAB批量提取参考 准备:数据说明 .csv数据如下: 打开某表格数据,如下:(需要说明的是此数据含表头) 需求说明:需…...
【软件】Ubuntu下QT的安装和使用
【软件】Ubuntu下QT的安装和使用 零、前言 QT是应用得比较广泛的程序框架,是因为其跨平台特性比较好,且用C/C作为开发语言,性能也比较好,故本文介绍如何安装和使用QT,用的版本是QT 6.2.4,由于QT在Windows…...
在Spring Boot中具有多个实现的接口正确注入的六种方式
博客主页: 南来_北往 系列专栏:Spring Boot实战 在Spring Boot中,当一个接口具有多个实现时,正确地将这些实现注入到需要使用它们的地方是一个常见的需求。以下是在Spring Boot中实现这一目标的六种方式: 1. 使用Autowir…...
登陆微软账户太慢了,如何解决
软账号登录慢解决办法: 打开“网络和Internet”选择“以太网”选择“更改适配器选项”选择现用网络,右键->属性选择“IPV4”右键属性更改DNS地址为以下两者4.2.2.14.2.2.2...
Vue3动态组件component不生效问题解决方法
问题: vue3循环渲染动态组件component不生效,页面空白 在vue3使用component动态组件展示组件时,组件就是不展示显示空白。在vue2中使用动态变量component展示组件都是没问题。试了很多方法 踩了很多坑,所以记录下: 登录…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...
comfyui 工作流中 图生视频 如何增加视频的长度到5秒
comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗? 在ComfyUI中实现图生视频并延长到5秒,需要结合多个扩展和技巧。以下是完整解决方案: 核心工作流配置(24fps下5秒120帧) #mermaid-svg-yP…...
DAY 45 超大力王爱学Python
来自超大力王的友情提示:在用tensordoard的时候一定一定要用绝对位置,例如:tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾: tensorboard的发展历史和原理tens…...
React父子组件通信:Props怎么用?如何从父组件向子组件传递数据?
系列回顾: 在上一篇《React核心概念:State是什么?》中,我们学习了如何使用useState让一个组件拥有自己的内部数据(State),并通过一个计数器案例,实现了组件的自我更新。这很棒&#…...
