无锁队列实现(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展示组件都是没问题。试了很多方法 踩了很多坑,所以记录下: 登录…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...

如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...