自扩充的无锁(Lock-Free)并发环形队列算法

c++ 高并发队列的实现 JAVA如何进行CAS 讲到java的队列时,讲到java中的CAS操作 回顾下java中的cas,主要采用compareAndSet方法,如AtomicReference中所使用的: AtomicRefrence.java /** * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * @param expect 阅读详情

注:这是好早就发资源上的了,现在看起来似乎有更好的方法,先发帖吧,有兴趣的可讨论再做修改。

文档下载:

http://download.youkuaiyun.com/download/guestcode/3022300



自扩充的Lock-Free并发环形队列算法

卢益贵 中国广西南宁市

QQ:48092788  E-Mail: gcode@qq.com Blog:http://blog.youkuaiyun.com/guestcode

(说明:因近段时候太多事情需要忙碌,自第一次起草到现在已经过了2个月了均未能成稿,只能简单描述了,暂时先占个坑先。部分阅读者看起来可能感觉吃力,相关资料可以搜索“Lock-Free Queue”关键词,阅读Lock-Free的相关文档后再阅读本文。2011-2-14 23:00)

摘要:此处省略512个字。

关键词:

自动扩充;锁无关;环形链表;并发环形队列

Auto Extern;Lock-Free;Circular Linked-List;ConcurrentCircular Queue

1、引言

环形链表具有避免申请释放节点元素的优点,但为了减少资源使用所以不能分配无穷大的节点数,只能根据具体需求分配一定数量的节点数,正因为如此,可能由于对系统分析不足而导致初始化的节点数不一定能满足队列的容量需求,这个时候就需要队列具有自适应的扩充队列节点数的功能,基于锁(Lock-Base)的算法实现扩充是相当容易的,但基于锁无关(Lock-Free)实现起来难度较大,下面将使用伪代码介绍基于Lock-Free实现可自适应扩充的环形并发队列算法,并提出了优化方案以使特定环境下能再提高队列效率。

2、类型定义(type define)

struct

{

int tag;

unsigned int atr;

}Data;

 

struct

{

int tag;

Node *ptr;

}Point;

 

struct

{

Node *next;

Data  data;

}Node;

3、变量定义(var define)

Point head, tail;

4、初始化(init)

Init()

{

    n1 = NewNode ();

n2 = NewNode ();

n3 = NewNode ();

//atr = 0表示该节点为空,非0为入列数值

n1.data.atr=n2.data.atr=n3.data.atr=0;

//三个节点组成环形链表

n1.next=n2;

n2.next=n3;

n3.next=n1;

head=tail=n1;

}

说明:tail永远指向空节点(atr=0),head.ptr不等于tail.ptr和head.ptr.data.atr不为0为队列非空的条件。

5、插入节点(insert node)

BOOL InserNode(Node *t,*n)

{//t和n之间插入一个节点

    Node *new = NewNode();

    if(!new)

        return(FALSE);

    new.data.atr = 0;

    new.next = n;

if(!CAS(&t.next, n, new))

    FreeNode(new);

return(TRUE);

}

6、入列(enqueue)

BOOL Enqueue(const TType data)

{//TType为任意32位的数值类型

    Point OldTail;

    Data OldData;

 

    //0不能入列

    if(0 == (unsignedint)data)

        return(FALSE);

    for(;;)

    {

        OldTail = tail;

        OldData = OldTail.ptr.data;

        if(OldTail != tail)

            continue;

        if(OldData != OldTail.ptr.data)

            continue;

        //追上头了

        if(OldTail.ptr.next == head.ptr)

        {

            //在头和尾之间插入一个节点

            if(InsertNode(OldTail.ptr,OldTail.ptr.next)

                continue;

            //插入失败

            return(FALSE);

}

//如果被占用了,我来移动队列尾指向下一个节点吧

if(OldData.atr)

{

    CAS(&tail, OldTail,<OldTail.ptr.next, OldTail.tag + 1>);

    continue;

}

//写入数据到队列尾

if(!CAS(&OldTail.data,OldData, <data, OldData.tag + 1>)

    continue;

//成功则队列尾移动到下一个节点

CAS(&tail,OldTail, <OldTail.ptr.next, OldTail.tag + 1>);

return(TRUE);

    }

}

7、出列(dequeue)

BOOL Dequeue(TType&data)

{//TType为任意32位的数值类型

    Point OldHead;

 

    for(;;)

    {

        OldHead = head;

        if(OldHead != head)

            continue;

        //头尾相等和atr=0表示队列为空

        (a)if((OldHead.ptr== tail.ptr) || (!OldHead.data.atr))

            return(FALSE);

        //头下移

        (b)if(!CAS(&head,OldHead, <OldHead.ptr.next, OldHead.tag + 1>)

            continue;

        //移成功,该节点被我(线程)独享,可以放心的读出数据和设置该节点为空了

        (c)data= OldHead.ptr.data.atr;

        (d)OldHead.ptr.data.atr= 0;

        return(TRUE);

    }

}

8、缺点和优化

本队列的缺点是入列的数据不能为0,解决的办法是将数据结构Data改为:

Struct

{

shorttag;

shortflag;

unsignedint atr;

}Data;

上面数据结构大小保持为64位,flag为0表示该节点为空,非0为该节点有数据,那么atr值即可为32位范围内的任意值,修改出入列代码中相关的判断语句即可。

另外,多次CAS也会降低性能,因此入列函数可以优化为一次CAS即可完成:

先修改Node结构(那么Data结构就可以省去了,可以修改出列相关代码):

struct

{

Node*next;

unsignedint  data;

}Node;

优化后的入列代码:

BOOL Enqueue(const TType data)

{

    Point OldTail;

 

    if(0 == (unsigned int)data)

        return(FALSE);

    for(;;)

    {

        OldTail= tail;

        if(OldTail!= tail)

            continue;

        //追上头了;或者下个节点还没有被置为空,则插入一个节点,防止重叠

        (e)if((OldTail.ptr.next == head.ptr) || (OldTail.ptr.next.data))

        {

            if(InsertNode(OldTail.ptr, OldTail.ptr.next)

                continue;

            return(FALSE);

}

//先将尾下移

(f)if(!CAS(&tail, OldTail, <OldTail.ptr.next,OldTail.tag + 1>))

        continue;

    //如果成功,那么我就可以独享该节点,放心的写入数据吧

(g)OldTail.ptr.data = data;

return(TRUE);

    }

}

注意:

优化后的入列函数在(f)和(g)之间,当前线程有可能会失去量程,导致该节点(g)未能先写入数据,而后面的的节点(OldTail.ptr.next)被别的线程先写入数据,造成队列为空(a)的假象,当然是几率问题了。尽管有缺陷,但可以用在特定环境下,比如在多核(CPU)指定内核(CPU)运行特定的单一线程,即可避免分时的几率就不会有失去量程的可能性。

同样,在出列函数的(b)和(c)之间也有一样的问题,但优化后的入列函数因为不会因为出列函数失去量程而导致for(;;)死等待到(d),因为优化后的入列函数(e)处有了判断,会插入一个节点,避免下移导致重叠确保tail永远指向空的节点。

 

9、结论

此处省略2048个字。

10、参考资料

此处省略1024个字。



 

C++并发编程实战中文翻译项目:开源协作与深度学习指南 并发编程是现代软件开发的核心技术,它允许多个计算任务同时执行,从而提升程序性能与资源利用率。其原理基于操作系统提供的线程、进程等抽象,通过同步原语(如互斥锁、条件变量)和内存模型来协调共享资源的访问,避免数据竞争与死锁。这项技术的价值在于能充分利用多核处理器,构建高吞吐、低延迟的响应式系统,广泛应用于服务器后端、游戏引擎、数据处理和高性能计算等领域。本文聚焦于《C++ Concurrency in Action》第二版的中文翻译项目,这是一个典型的开源协作知识工程。项目不仅系统讲解了C++11/14/17标 阅读详情

相关推荐

【信息科学与工程学】【运营科学】第二篇 C4信息与通信网络运营 (C4) ——数据中心网络运营04

典型值:λ1​∈[−0.02,−0.01], λ2​∈[−0.01,0], η1​,η3​∈[0.1,0.3], η2​,η4​∈[0.05,0.15]参数:δ1​∈[−0.8,−0.3], δ2​∈[−0.5,−0.2], δ3​∈[−0.4,−0.1], δ4​∈[−0.6,−0.2]参数:φ1​∈[0.1,0.3], φ2​∈[−0.2,−0.05], φ3​∈[−0.1,0.1], φ4​∈[−0.3,−0.1]参数:α∈[0.3,0.6], β∈[0.2,0.4], γ∈[0.01,0.03]

weixin_49199313的博客 1203

无锁队列的实现

为什么需要无锁队列 无锁队列解决了什么问题?无锁队列解决了锁引起的问题。 cache失效 当CPU要访问主存的时候,这些数据首先要被copy到cache中,因为这些数据在不久的将来可能又会被处理器访问;CPU访问cache的速度要比访问内存要快的多;由于线程频繁切换,会造成cache失效,将导致应用程序性能下降。 阻塞引起的CPU浪费 mutex是阻塞的,在一个负载较重的应用程序中使用阻塞队列来在线程之间传递消息,会导致频繁的线程切换,大量的时间将被浪费在获取mutex,而不是处理任务上。 这就需要非阻塞来

congchp的博客 2059

对比学习损失函数避坑指南:为什么你的自监督模型不收敛?

本文深入剖析对比学习损失函数中的关键陷阱,揭示自监督模型不收敛的根本原因。通过分析温度系数选择、负样本采样策略和特征归一化等核心因素,提供实用解决方案。实验数据表明,正确设置温度系数τ(建议0.07起)可提升30%性能,而MoCo风格的负样本队列比SimCLR方案在小批量时准确率高6-8%。

nokia的博客 922

无锁队列概述

一、无锁队列原理 1、队列操作模型 队列是一种非常重要的数据结构,其特性是先进先出(FIFO),符合流水线业务流程。在进程间通信、网络通信间经常采用队列做缓存,缓解数据处理压力。 根据操作队列的场景分为:单生产者——单消费者、多生产者——单消费者、单生产者——多消费者、多生产者——多消费者四大模型。根据队列中数据分为:队列中的数据是定长的、队列中的数据是变长的。 (1)单生产者——单消费者 (2)多生产者——单消费者 (3)单生产者——多消费者 ...

jamin_liu_90的博客 9598

头歌平台 操作系统课堂练习2.3:系统调用

使用 gdb 调试内核,跟踪到 main 函数入口的方法与之前实训一样。系统运行时,执行的前 3 个系统调用的编号和名字分别是什么?系统运行时,执行的前 3 个系统调用的编号和名字分别是什么?本关卡使用版本 1 内核进行分析,版本 1 内核文件存放在。为了完成本关任务,你需要:跟踪系统调用的发生。此时,系统调用号存放在寄存器 eax 中。

lazbuyaotoutu的博客 2万+

工业焊缝缺陷检测实战:我用PatchCore在自建数据集上踩过的那些坑

本文详细介绍了PatchCore算法在工业焊缝缺陷检测中的实战应用,包括数据准备、模型调参和阈值优化等关键环节。通过分析焊缝图像的特殊性和anomaly detection技术的优化策略,分享了在自建数据集上提升检测精度的实用经验,为工业质检领域提供有价值的参考方案。

weixin_42624889的博客 396

多线程无锁算法之无锁队列的实现

多线程无锁算法之无锁队列的实现 今天花了近两个小时的时间好好的理解了一下多线程无锁队列的实现,查看了很多资料和文献。在我看来,实现无锁队列的关键点有二: 1、各个平台的原子操作或者说CAS原语; 2、ABA问题的理解和解决。 首先来说说这个CAS原语,所谓CAS(Compare And Swap)即比较并交换,在 Intel 处理器中,比较并交换通过指令的 cmpxchg 系列实现。

ljh081231的专栏 1万+

Maven

是一款自动化构建工具,专注于Java项目的构建、依赖的管理。

weixin_58738870的博客 2161

无锁消息队列实现

在实现无锁队列前,要知道无锁队列并不是真正意义上的无锁,无锁队列(Lock-Free Queue在概念上是指在实现队列数据结构时,不依赖于传统的互斥锁(如 mutex)来保证线程安全,尽管称为“无锁”,但这并不意味着完全没有同步机制。相反,它使用了底层硬件提供的原子指令来实现更细粒度的同步,从而提高并发性能。无锁队列的设计通常比基于锁的队列更加复杂,但在高并发场景下可以提供更好的性能和可伸缩性。

weixin_55951019的博客 1247

设计数据库 ER 图太麻烦?不妨试试这两款工具,自动生成数据库 ER 图!!!

告别手动画图,提高效率~

楼下小黑哥 2万+

Unity 面试篇⚠️ | Unity性能优化好,山寨机都能跑~

Unity 面试篇⚠️ | Unity性能优化好,山寨机都能跑~

m0_58523831的博客 1万+

并发无锁队列学习(概念介绍)

1、前言   队列在计算机中非常重要的一种数据结构,尤其在操作系统中。队列典型的特征是先进先出(FIFO),符合流水线业务流程。在进程间通信、网络通信之间经常采用队列做缓存,缓解数据处理压力。结合自己在工作中遇到的队列问题,总结一下对不同场景下的队列实现。根据操作队列的场景分为:单生产者——单消费者、多生产者——单消费者、单生产者——多消费者、多生产者——多消费者四大模型。其实后面三种的队列,可以归纳为一种多对多。根据队列中数据分为:队列中的数据是定长的、队列中的数据是变长的。 2、队列操作模型 (1

木牛的博客 379

C/C++李峋同款跳动的爱心代码(完整代码)

C++语言实现出李峋同款跳动的爱心的完整代码。

AIGC 10万+

lock-free介绍

无锁编程 / lock-free / 非阻塞同步 无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。 实现非阻塞同步的方案称为“无锁编程算法”( Non-blocking algorithm)。 lock-free是目前最常见的无锁编程的实现级别(一共三种级别)。...

MyObject-C的专栏 1万+

QGIS安装与使用教程

QGIS安装与使用教程

weixin_46713695的博客 2万+

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

高效C++无锁(lock free)队列moodycamel::ConcurrentQueue

moodycamel::ConcurrentQueue一种用C++11实现的多生产者、多消费者无锁队列。它具有以下特点:1.快的让人大吃一惊,详见2.单头文件实现,很容易集成到你的项目中3.完全线程安全的无锁队列,支持任意线程数的并发4.用C++11实现,尽可能move元素,而不是copy元素5.模板化,无需专门处理指针,内部自动管理内存6.对元素类型或最大计数没有人为限制7.内存可以预先一次分配,也可以根据需要动态分配8.跨平台,所有操作都通过标准C++11原语完成。

草上爬的博客 1万+

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

【上机实验】03:循环队列与扩容

循环队列与扩容 1.顺序队列操作 #include<stdio.h> #include<stdlib.h> #include<time.h> typedef struct{ int *data; int front, rear; int length; }SqQueue; //1.队列初始化 SqQueue *InitQueue(int n){ SqQueue *sq = (SqQueue *)malloc(sizeof(SqQueu

https://blog.youkuaiyun.com/m0_74834215 1688

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

无锁队列(Lock-Free Queue)

无锁队列(Lock-Free Queue)是一种不使用锁机制(如互斥锁或读写锁)来实现线程安全的数据结构,是lock-free中最基本的数据结构。它通过复杂的原子操作(如CAS操作,在C++中,可以使用库提供的原子操作)来确保在多线程环境下的正确性和一致性。无锁队列的设计目标是在高并发场景下提供高性能的入队和出队操作,避免了锁机制带来的性能开销和潜在的死锁问题。对于多线程用户来说,无锁队列的入队和出队操作是线程安全的,无需再加锁控制。

笨死的猪Blog 1万+

并发无锁队列

并发无锁队列学习之一【开篇】 1、前言      队列在计算机中非常重要的一种数据结构,尤其在操作系统中。队列典型的特征是先进先出(FIFO),符合流水线业务流程。在进程间通信、网络通信之间经常采用队列做缓存,缓解数据处理压力。结合自己在工作中遇到的队列问题,总结一下对不同场景下的队列实现。根据操作队列的场景分为:单生产者——单消费者、多生产者——单消费者、单生产者——多消费者、多生产者——多消费...

weixin_34291004的博客 410

详解高性能无锁队列的实现

无锁队列(Lock-Free Queue)是一种并发数据结构,它允许多个线程在没有锁的情况下进行并发操作。传统的队列通常通过互斥锁来实现线程安全的操作,但互斥锁在高并发情况下可能会造成竞争和性能瓶颈。为了避免使用锁,无锁队列采用了基于原子操作的并发算法。无锁队列的设计目标是在保持线程安全的前提下提供高性能的并发操作。它通常使用 CAS(Compare and Swap)等原子指令来实现对队列头部和尾部指针的更新和操作。CAS 操作可以确保只有一个线程能够成功修改指针,其他线程则需要重试或者尝试其他操作。

Ricardo2的博客 2514

【高并发】多线程之无锁队列|无锁队列kfifo|性能优化

队列操作模型 (1)单生产者——单消费者 (2)多生产者——单消费者 (3)单生产者——多消费者 (4)多生产者——多消费者 3、队列数据定长与变长 (1)队列数据定长 (2)队列数据变长 并发无锁处理 (1)单生产者——单消费者模型   此种场景不需要加锁,定长的可以通过读指针和写指针进行控制队列操作,变长的通过读指针、写指针、结束指针控制......

我的笔记本 3680

Linux内核数据结构 —— 无锁环形队列 ( kfifo )

Linux内核数据结构 —— 无锁环形队列 ( kfifo )

qq_23174771的博客 7521

有锁队列、无锁队列

【代码】有锁队列、无锁队列。

weixin_44585214的博客 1532

无锁(Lock-Free)编程简介及漫谈

一、引言 现代计算机,即使很小的智能机亦或者平板电脑,都是一个多核(多CPU)处理设备,如何充分利用多核CPU资源,以达到单机性能的极大化成为我们码农进行软件开发的痛点和难点。在多核服务器中,采用多进程或多线程来并行处理任务,俨然成为了大家性能调优的标准解决方案。多进程(多线程)的并行编程方式,必然要面对共享数据的访问问题,如何并发、高效、安全地访问共享数据资源,成为并行编程的一个重点和难点。 传统的共享数据访问方式是采用同步原语(临界区、锁、条件变量等)来达到共享数据的安全访问,然而,同步恰恰和并行

smilejiasmile的博客 7186

眉目传情之并发无锁环形队列的实现

前面在《眉目传情之匠心独运的kfifo》一文中详细解析了 linux 内核并发无锁环形队列kfifo的原理和实现,kfifo鬼斧神工,博大精深,让人叹为观止,但遗憾的是kfifo为内核提供服务,并未开放出来。剑不试则利钝暗,弓不试则劲挠诬,鹰不试则巧拙惑,马不试则良驽疑,光说不练是不能学到精髓的,下面就动手实现自己的并发无锁队列UnlockQueue(单生产者单消费者)。

@Echo· 个人技术笔记 2万+
上一篇: 沉默3年了,该写点什么呢——什么是网络通讯?
下一篇: G-Sockets2.5 发布说明
ygluu
博客等级 码龄17年 300粉丝 62原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值