https://www.oschina.net/translate/a-fast-lock-free-queue-for-cpp?cmp&p=2

A single-producer, single-consumer lock-free queue for C++

如果没有可靠的(已被测试的)实现,设计又有什么用呢?:-)

我已经 在GitHub发布了我的实现。 自由的fork它吧!它由两个头部组成,一个是给队列的,还有一个取决于是否包含一些辅助参数。

它具有几个优异的特性:

  • 与 C++11兼容 (支持移动对象而不是做拷贝)
  • 完全通用 (任何类型的模板化容器) -- 就像std::queue,你从不需要自己给元素分配内存 (这将你从为了管理正在排队的元素而去写锁无关的内存管理单元的麻烦中解脱出来)
  • 以连续的块预先分配内存
  • 提供 atry_enqueue方法,该方法保证不去分配内存 (队列以初始容量起动)
  • 也提供了一个enqueue方法,该方法能够根据需要动态的增长队列的大小
  • 不采用比较-交换循环;这意味着 enqueue和dequeue是O(1)复杂度 (不计算内存分配)
  • 对于x86设备, 内存屏障编译为空指令,这意味着enqueue与dequeue仅仅只是简单的loads和stores序列 (以及 branches)
  • 在 MSVC2010+ 和 GCC 4.7+下编译 (而且应该工作于任何支持 C++11 的编译器)
It should be noted that this code will only work on CPUs that treat aligned integer and native-pointer-size loads/stores atomically; fortunately, this includes every modern processor (including ARM, x86/x86-64, and PowerPC). It is not designed to work on the DEC Alpha (which seems to have the weakest memory-ordering guarantees of all time).

I'm releasing the code and algorithm under the terms of the simplified BSD license. Use it at your own risk; in particular, lock-free programming is a patent minefield, and this code may very well violate a pending patent (I haven't looked). It's worth noting that I came up with the algorithm and implementation from scratch, independent of any existing lock-free queues.

译者信息

赵亮-碧海情天

翻译于 2013/05/30 17:56

1 人 此译文

应注意的是,此代码只能工作于能处理对齐的整数和原生指针长度的负载/存储原子的CPU;幸运的是,这包括所有的现代处理器(包括 ARM,x86 / x86-64,和PowerPC)。它不能工作于 DEC Alpha(这玩意内存排序能力保证最弱)。

我发布的代码和算法遵循简化的BSD授权协议。你需要自己承担使用风险;特别是,无锁编程是一个专利的雷区,这代码很可能违反了专利(我还没查验)。需要提出的是,我是自己胡乱写出来的算法和实现,与任何现有的无锁队列无关。

Performance and correctness

In addition to agonizing over the design for quite some time, I tested the algorithm using several billion randomized operations in a simple stability test (on x86). This, of course, helps inspire confidence, but proves nothing about the correctness. In order to ensure it was correct, I also tested using Relacy, which ran all the possible interleavings for a simple test which turned up no errors; it turns out this simple test wasn't comprehensive, however, since I eventually did find a bug later using a different set of randomized runs (which I then fixed).

I've only tested this queue on x86-64, which is rather forgiving as memory ordering goes. If somebody is willing to test this code on another architecture, let me know! The quick stability test I whipped up is available here.

译者信息

MtrS

翻译于 2013/05/31 11:59

1 人 此译文

性能测试和无误较正

除了折腾在相当长的一段时间的设计,我(X86)测试了一个简单的稳定性测试使用数十亿随机操作的算法。 当然,这有助于鼓舞信心,但不能证明什么的正确性。 为了确保它是正确的,我的测试也使用了Relacy,跑了一个简单的测试来测试所有可能的交错。没有发现错误;但是,事实证明这个简单的测试是不全面的,因为通过使用一组不同的随机运行,我发现了一个错误(当然我最后修正了这些)。

我只在x86-64架构的机器上测试此队列,内存占用是相当宽裕(少)的。如有人乐意在其他架构机器上测试这些代码,告诉我吧。快速稳定性的测试代码我放在了这儿 。

In terms of performance, it's fast. Really fast. In my tests, I was able to get up to about 12+ million concurrent enqueue/dequeue pairs per second! (The dequeue thread had to wait for the enqueue thread to catch up if there was nothing in the queue.) After I had implemented my queue, though, I found another single-consumer, single-producer templated queue (written by the author of Relacy) published on Intel's website; his queue is roughly twice as fast, though it doesn't have all the features that mine does, and his only works on x86 (and, at this scale, "twice as fast" means the difference in enqueue/dequeue time is in the nanosecond range).

Update16 days ago

I spent some time properly benchmarking, profiling, and optimizing the code, using Dmitry's single-producer, single-consumer lock-free queue (published on Intel's website) as a baseline for comparison. Mine's now faster in general, particularly when it comes to enqueueing many elements (mine uses a contiguous block instead of separate linked elements). Note that different compilers give different results, and even the same compiler on different hardware yields significant speed variations. The 64-bit version is generally faster than the 32-bit one, and for some reason my queue is much faster under GCC on a Linode. Here are the benchmark results in full:

32-bit, MSVC2010, on AMD C-50 @ 1GHz
------------------------------------
| Min | Max | Avg
Benchmark | RWQ | SPSC | RWQ | SPSC | RWQ | SPSC | Mult
------------------+---------+---------+---------+---------+---------+---------+------
Raw add | 0.0039s | 0.0268s | 0.0040s | 0.0271s | 0.0040s | 0.0270s | 6.8x
Raw remove | 0.0015s | 0.0017s | 0.0015s | 0.0018s | 0.0015s | 0.0017s | 1.2x
Raw empty remove | 0.0048s | 0.0027s | 0.0049s | 0.0027s | 0.0048s | 0.0027s | 0.6x
Single-threaded | 0.0181s | 0.0172s | 0.0183s | 0.0173s | 0.0182s | 0.0173s | 0.9x
Mostly add | 0.0243s | 0.0326s | 0.0245s | 0.0329s | 0.0244s | 0.0327s | 1.3x
Mostly remove | 0.0240s | 0.0274s | 0.0242s | 0.0277s | 0.0241s | 0.0276s | 1.1x
Heavy concurrent | 0.0164s | 0.0309s | 0.0349s | 0.0352s | 0.0236s | 0.0334s | 1.4x
Random concurrent | 0.1488s | 0.1509s | 0.1500s | 0.1522s | 0.1496s | 0.1517s | 1.0x Average ops/s:
ReaderWriterQueue: 23.45 million
SPSC queue: 28.10 million 64-bit, MSVC2010, on AMD C-50 @ 1GHz
------------------------------------
| Min | Max | Avg
Benchmark | RWQ | SPSC | RWQ | SPSC | RWQ | SPSC | Mult
------------------+---------+---------+---------+---------+---------+---------+------
Raw add | 0.0022s | 0.0210s | 0.0022s | 0.0211s | 0.0022s | 0.0211s | 9.6x
Raw remove | 0.0011s | 0.0022s | 0.0011s | 0.0023s | 0.0011s | 0.0022s | 2.0x
Raw empty remove | 0.0039s | 0.0024s | 0.0039s | 0.0024s | 0.0039s | 0.0024s | 0.6x
Single-threaded | 0.0060s | 0.0054s | 0.0061s | 0.0054s | 0.0061s | 0.0054s | 0.9x
Mostly add | 0.0080s | 0.0259s | 0.0081s | 0.0263s | 0.0080s | 0.0261s | 3.3x
Mostly remove | 0.0092s | 0.0109s | 0.0093s | 0.0110s | 0.0093s | 0.0109s | 1.2x
Heavy concurrent | 0.0150s | 0.0175s | 0.0181s | 0.0200s | 0.0165s | 0.0190s | 1.2x
Random concurrent | 0.0367s | 0.0349s | 0.0369s | 0.0352s | 0.0368s | 0.0350s | 1.0x Average ops/s:
ReaderWriterQueue: 34.90 million
SPSC queue: 32.50 million 32-bit, MSVC2010, on Intel Core 2 Duo T6500 @ 2.1GHz
----------------------------------------------------
| Min | Max | Avg
Benchmark | RWQ | SPSC | RWQ | SPSC | RWQ | SPSC | Mult
------------------+---------+---------+---------+---------+---------+---------+------
Raw add | 0.0011s | 0.0097s | 0.0011s | 0.0099s | 0.0011s | 0.0098s | 9.2x
Raw remove | 0.0005s | 0.0006s | 0.0005s | 0.0006s | 0.0005s | 0.0006s | 1.1x
Raw empty remove | 0.0018s | 0.0011s | 0.0019s | 0.0011s | 0.0018s | 0.0011s | 0.6x
Single-threaded | 0.0047s | 0.0040s | 0.0047s | 0.0040s | 0.0047s | 0.0040s | 0.9x
Mostly add | 0.0052s | 0.0114s | 0.0053s | 0.0116s | 0.0053s | 0.0115s | 2.2x
Mostly remove | 0.0055s | 0.0067s | 0.0056s | 0.0068s | 0.0055s | 0.0068s | 1.2x
Heavy concurrent | 0.0044s | 0.0089s | 0.0075s | 0.0128s | 0.0066s | 0.0107s | 1.6x
Random concurrent | 0.0294s | 0.0306s | 0.0295s | 0.0312s | 0.0294s | 0.0310s | 1.1x Average ops/s:
ReaderWriterQueue: 71.18 million
SPSC queue: 61.02 million 64-bit, MSVC2010, on Intel Core 2 Duo T6500 @ 2.1GHz
----------------------------------------------------
| Min | Max | Avg
Benchmark | RWQ | SPSC | RWQ | SPSC | RWQ | SPSC | Mult
------------------+---------+---------+---------+---------+---------+---------+------
Raw add | 0.0007s | 0.0097s | 0.0007s | 0.0100s | 0.0007s | 0.0099s | 13.6x
Raw remove | 0.0004s | 0.0015s | 0.0004s | 0.0020s | 0.0004s | 0.0018s | 4.6x
Raw empty remove | 0.0014s | 0.0010s | 0.0014s | 0.0010s | 0.0014s | 0.0010s | 0.7x
Single-threaded | 0.0024s | 0.0022s | 0.0024s | 0.0022s | 0.0024s | 0.0022s | 0.9x
Mostly add | 0.0031s | 0.0112s | 0.0031s | 0.0115s | 0.0031s | 0.0114s | 3.7x
Mostly remove | 0.0033s | 0.0041s | 0.0033s | 0.0041s | 0.0033s | 0.0041s | 1.2x
Heavy concurrent | 0.0042s | 0.0035s | 0.0067s | 0.0039s | 0.0054s | 0.0038s | 0.7x
Random concurrent | 0.0142s | 0.0141s | 0.0145s | 0.0144s | 0.0143s | 0.0142s | 1.0x Average ops/s:
ReaderWriterQueue: 101.21 million
SPSC queue: 71.42 million 32-bit, Intel ICC 13, on Intel Core 2 Duo T6500 @ 2.1GHz
--------------------------------------------------------
| Min | Max | Avg
Benchmark | RWQ | SPSC | RWQ | SPSC | RWQ | SPSC | Mult
------------------+---------+---------+---------+---------+---------+---------+------
Raw add | 0.0014s | 0.0095s | 0.0014s | 0.0097s | 0.0014s | 0.0096s | 6.8x
Raw remove | 0.0007s | 0.0006s | 0.0007s | 0.0007s | 0.0007s | 0.0006s | 0.9x
Raw empty remove | 0.0028s | 0.0013s | 0.0028s | 0.0018s | 0.0028s | 0.0015s | 0.5x
Single-threaded | 0.0039s | 0.0033s | 0.0039s | 0.0033s | 0.0039s | 0.0033s | 0.8x
Mostly add | 0.0049s | 0.0113s | 0.0050s | 0.0116s | 0.0050s | 0.0115s | 2.3x
Mostly remove | 0.0051s | 0.0061s | 0.0051s | 0.0062s | 0.0051s | 0.0061s | 1.2x
Heavy concurrent | 0.0066s | 0.0036s | 0.0084s | 0.0039s | 0.0076s | 0.0038s | 0.5x
Random concurrent | 0.0291s | 0.0282s | 0.0294s | 0.0287s | 0.0292s | 0.0286s | 1.0x Average ops/s:
ReaderWriterQueue: 55.65 million
SPSC queue: 63.72 million 64-bit, Intel ICC 13, on Intel Core 2 Duo T6500 @ 2.1GHz
--------------------------------------------------------
| Min | Max | Avg
Benchmark | RWQ | SPSC | RWQ | SPSC | RWQ | SPSC | Mult
------------------+---------+---------+---------+---------+---------+---------+------
Raw add | 0.0010s | 0.0099s | 0.0010s | 0.0100s | 0.0010s | 0.0099s | 9.8x
Raw remove | 0.0006s | 0.0015s | 0.0006s | 0.0018s | 0.0006s | 0.0017s | 2.7x
Raw empty remove | 0.0024s | 0.0016s | 0.0024s | 0.0016s | 0.0024s | 0.0016s | 0.7x
Single-threaded | 0.0026s | 0.0023s | 0.0026s | 0.0023s | 0.0026s | 0.0023s | 0.9x
Mostly add | 0.0032s | 0.0114s | 0.0032s | 0.0118s | 0.0032s | 0.0116s | 3.6x
Mostly remove | 0.0037s | 0.0042s | 0.0037s | 0.0044s | 0.0037s | 0.0044s | 1.2x
Heavy concurrent | 0.0060s | 0.0092s | 0.0088s | 0.0096s | 0.0077s | 0.0095s | 1.2x
Random concurrent | 0.0168s | 0.0166s | 0.0168s | 0.0168s | 0.0168s | 0.0167s | 1.0x Average ops/s:
ReaderWriterQueue: 68.45 million
SPSC queue: 50.75 million 64-bit, GCC 4.7.2, on Linode 1GB virtual machine (Intel Xeon L5520 @ 2.27GHz)
-----------------------------------------------------------------------------
| Min | Max | Avg
Benchmark | RWQ | SPSC | RWQ | SPSC | RWQ | SPSC | Mult
------------------+---------+---------+---------+---------+---------+---------+------
Raw add | 0.0004s | 0.0055s | 0.0005s | 0.0055s | 0.0005s | 0.0055s | 12.1x
Raw remove | 0.0004s | 0.0030s | 0.0004s | 0.0030s | 0.0004s | 0.0030s | 8.4x
Raw empty remove | 0.0009s | 0.0060s | 0.0010s | 0.0061s | 0.0009s | 0.0060s | 6.4x
Single-threaded | 0.0034s | 0.0052s | 0.0034s | 0.0052s | 0.0034s | 0.0052s | 1.5x
Mostly add | 0.0042s | 0.0096s | 0.0042s | 0.0106s | 0.0042s | 0.0103s | 2.5x
Mostly remove | 0.0042s | 0.0057s | 0.0042s | 0.0058s | 0.0042s | 0.0058s | 1.4x
Heavy concurrent | 0.0030s | 0.0164s | 0.0036s | 0.0216s | 0.0032s | 0.0188s | 5.8x
Random concurrent | 0.0256s | 0.0282s | 0.0257s | 0.0290s | 0.0257s | 0.0287s | 1.1x Average ops/s:
ReaderWriterQueue: 137.88 million
SPSC queue: 24.34 million

In short, my queue is blazingly fast, and actually doing anything with it will eclipse the overhead of the data structure itself.

The benchmarking code is available here (compile and run with full optimizations).

 

readerwriterqueue 一个用 C++ 实现的快速无锁队列的更多相关文章

  1. 一个可无限伸缩且无ABA问题的无锁队列

    关于无锁队列,详细的介绍请参考陈硕先生的<无锁队列的实现>一文.然进一步,如何实现一个不限node数目即能够无限伸缩的无锁队列,即是本文的要旨. 无锁队列有两种实现形式,分别是数组与链表. ...

  2. boost 无锁队列

    一哥们翻译的boost的无锁队列的官方文档 原文地址:http://blog.csdn.net/great3779/article/details/8765103 Boost_1_53_0终于迎来了久 ...

  3. Erlang运行时中的无锁队列及其在异步线程中的应用

    本文首先介绍 Erlang 运行时中需要使用无锁队列的场合,然后介绍无锁队列的基本原理及会遇到的问题,接下来介绍 Erlang 运行时中如何通过“线程进度”机制解决无锁队列的问题,并介绍 Erlang ...

  4. 聊一聊无锁队列rte_ring

    之前用基于dpdk 实现小包快速转发的时候有用到无锁队列!今天就来看看吧!(后续完成了去dpdk化,直接在内核完成快速转发功能) dpdk的无锁队列ring是借鉴了linux内核kfifo无锁队列.r ...

  5. 无锁队列以及ABA问题

    队列是我们非常常用的数据结构,用来提供数据的写入和读取功能,而且通常在不同线程之间作为数据通信的桥梁.不过在将无锁队列的算法之前,需要先了解一下CAS(compare and swap)的原理.由于多 ...

  6. zeromq源码分析笔记之无锁队列ypipe_t(3)

    在上一篇中说到了mailbox_t的底层实际上使用了管道ypipe_t来存储命令.而ypipe_t实质上是一个无锁队列,其底层使用了yqueue_t队列,ypipe_t是对yueue_t的再包装,所以 ...

  7. 无锁队列--基于linuxkfifo实现

    一直想写一个无锁队列,为了提高项目的背景效率. 有机会看到linux核心kfifo.h 原则. 所以这个实现自己仿照,眼下linux我们应该能够提供外部接口. #ifndef _NO_LOCK_QUE ...

  8. CAS简介和无锁队列的实现

    Q:CAS的实现 A:gcc提供了两个函数 bool __sync_bool_compare_and_swap (type *ptr, type oldval, type newval, ...)// ...

  9. Go语言无锁队列组件的实现 (chan/interface/select)

    1. 背景 go代码中要实现异步很简单,go funcName(). 但是进程需要控制协程数量在合理范围内,对应大批量任务可以使用"协程池 + 无锁队列"实现. 2. golang ...

随机推荐

  1. 使用svn遇到的问题---(在编辑器没有配置svn的前提下)

    日常写代码的过程中新增了文件,一般都是继续文件的书写,写完一部分后提交 新增文件后面经常忘记了add后commit 原来是可以在commit时勾选左下角的 [show unversioned file ...

  2. git托管代码

    安装git 在github上创建仓库 搞钥匙 在vscode上托管 初次在不同电脑上上传代码报错 解决:git pull --rebase origin master 链接:https://blog. ...

  3. NativeScript —— 初级入门(跨平台的手机APP应用)《一》

    NativeScript简介 NativeScript是一个相当新的开源开发系统,几乎完全用JavaScript创建跨平台移动应用程序,带有一些可选的CSS和XML来简化显示布局的开发.您可以在htt ...

  4. Scrapy框架之Spider模板 转

    一.安装scrapy 首先安装依赖库Twisted pip install (依赖库的路径) 在这个网址http://www.lfd.uci.edu/~gohlke/pythonlibs#twiste ...

  5. WinForm - 不用自绘实现仿QQ2013

    素材啥的都是一手整理的,绝对的原创.这是13年做的,虽然是个老项目了,可里面涉及的winform技术不会过时,所以就拿出来重温探讨下技术要点. 没使用任何自绘命令,可以说是非常容易理解与学习的. 效果 ...

  6. getAttribute和getParameter的简单区别

    getAttribute表示从request范围取得设置的属性,必须要先setAttribute设置属性,才能通过getAttribute来取得,设置与取得的为Object对象类型 getParame ...

  7. SeekBar 滚动条

    原seek_thumb样式----------------------------------------------------------------------↑↑↑↑↑ android:thu ...

  8. Hadoop_08_客户端向HDFS读写(上传)数据流程

    1.HDFS的工作机制: HDFS集群分为两大角色:NameNode.DataNode (Secondary Namenode) NameNode负责管理整个文件系统的元数据 DataNode 负责管 ...

  9. python基础编程:生成器、迭代器、time模块、序列化模块、反序列化模块、日志模块

    目录: 生成器 迭代器 模块 time 序列化 反序列化 日志 一.生成器 列表生成式: a = [1,2,3,3,4,5,6,7,8,9,10] a = [i+1 for i in a ] prin ...

  10. Gym - 101955E The Kouga Ninja Scrolls (曼哈顿距离变换+线段树)

    题意:有n个忍者(编号为1-n),每个忍者有三个属性:横坐标x,纵坐标y,所属门派c,要求支持三种操作: 1.改变第k个忍者的位置 2.改变第k个忍者的门派 3.查询编号为[l,r]之间的忍者中,所属 ...