多线程下使用数组保存数据,必须先对数组进行加锁,本文介绍 即时通讯软件 的无锁数组操作。

在之前的两篇博客(线程安全的无锁RingBuffer的实现,多个写线程一个读线程的无锁队列实现)中,分别写了在只有一个读线程、一个写线程的情况下,以及只有一个写线程、两个读线程的情况下,不采用加锁技术,甚至原子运算的循环队列的实现。但是,在其他的情况下,我们也需要尽可能高效的线程安全的队列的实现。本文实现了一种基于循环数组和原子运算的无锁队列。采用原子运算(compare and swap)而不是加锁同步,可以很大的提高运行效率。之所以用循环数组,是因为这样在使用过程中不需要反复开辟内存空间,可以达到较好的效率。本文的实现参考了论文Implementing Lock-Free Queues所提到的方法。但是,在这篇论文中,作者并没有给出具体的实现。本文的 即时通讯软件 实现也和论文中的方法有所不同。本文的实现基于Windows操作系统,代码在Visual Studio 2010下测试通过。

本文的实现基于compare and swap这个原子操作,简写为CAS。其原型为

long CAS(long* ptr, long old_value, long new_value).

其操作为,如果ptr所指向的变量和old_value相等,则将其置为new_value. 否则什么也不做。返回值为ptr所指向的变量。

本文提出的方法的基本原理如下。代码会在其后附上。

首先,我们约定,有一个特殊的数值,叫做EMPTY,存入数组的所有数都不能是这个数值。在一开始,将整个buffer的值都初始化为EMPTY.

第二,以两个变量,readCnt和writeCnt,来记录读和写的次数。这两个数模数组长度,就可以得到下一次读和写的位置。如果readCnt和writeCnt模buffer大小相等,则说明当前队列为控;而如果在写的位置不是EMPTY,则说明buffer已满。

第三,也就是最重要的,线程同步的原理。在进行写buffer操作时,首先通过CAS操作将buffer对应位置置为指定值,而writeCnt不变,因此其他线程无法在同样的位置进行写操作,这样防止了其他写线程的覆盖。而由于此时writeCnt还没有变,读线程此时也无法读该位置的数据,这样防止了其他读线程的冲突。接下来,第二步,则是通过CAS操作,将writeCnt加一。可以看到,代码中在第一个CAS操作失败的情况下,会执行一个增大writeCnt的原子操作。这样做的目的是避免某个线程停掉导致其他所有线程都停掉。

而在进行写操作时,首先通过判断readCnt和writeCnt是否相等来判断当前队列是否已满。这样做的原因如前所述,是为了避免和写线程之间的冲突。接下来,如果当前位置可以读,则通过一个CAS操作将readCnt加一。这样,其他读线程就无法再读这个位置。而由于这个位置值还不是EMPTY,其他写线程也无法写这个位置。接下来,在读走数值之后,再通过CAS操作将buffer中的这个位置置为EMPTY. 此时,写线程可以在这个位置写入数据。

但是,这个 即时通讯软件 实现其实还有点问题。如果读线程比较多,例如,读线程个数和数组长度一样,就可能两个读线程同时读同一个位置。这样的读冲突这个程序是无法避免的。另外,如果读数据过程中有一个读线程停掉了,那么其他线程在读或者写到这个位置时,也会被阻塞。

原文地址:http://www.nanshan.biz/thread-13079-1-1.html



即时通讯软件 的无锁数组操作相关推荐

  1. 实现无锁的栈与队列(1)

    为了实现一个快速无锁的 logging 模块, 这几天花了不少时间去了解怎样实现一些无锁的操作及与之相对应的数据结构.对多线程场景下的无锁操作的研究一直是个热点,理想中的无锁操作,它应能天然地避开有锁 ...

  2. 垃圾回收算法与实现系列-JVM无锁实现

    导语   为了确保多线程场景下数据安全,使用锁机制一直是一种优秀的解决方案,但是再高并发场景下,对锁的竞争可能成为性能瓶颈.为此,有出现了一种新的解决方案,被称为是非阻塞同步的方案.这种实现方式不需要 ...

  3. 12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁

    小陈:呼叫老王...... 老王:来了来了,小陈你准备好了吗?今天我们来讲synchronized的锁重入.锁优化.和锁升级的原理 小陈:早就准备好了,我现在都等不及了 老王:那就好,那我们废话不多说 ...

  4. 基于数组的无锁队列(译)

    2019独角兽企业重金招聘Python工程师标准>>> 1 引言 最近对于注重性能的应用程序,我们有了一种能显著提高程序性能的选择:多线程.线程的概念实际上已经存在了很长时间.在过去 ...

  5. 无锁数据结构--理解CAS、ABA、环形数组

    在分布式系统中经常会使用到共享内存,然后多个进程并行读写同一块共享内存,这样就会造成并发冲突的问题, 一般的常规做法是加锁,但是锁对性能的影响非常大. 无锁队列是一个非常经典的并行计算数据结构,它极大 ...

  6. java 无锁缓存_如何在高并发环境下设计出无锁的数据库操作(Java版本)

    一个在线2k的游戏,每秒钟并发都吓死人.传统的hibernate直接插库基本上是不可行的.我就一步步推导出一个无锁的数据库操作. 1. 并发中如何无锁. 一个很简单的思路,把并发转化成为单线程.Jav ...

  7. CAS操作与无锁队列

    在多线程编程中,为了保证内存的可见性,我们加入了一些锁的机制,例如信号量,互斥锁,条件变量等等,但是锁的机制不是一个简单的机制,需要加入很多的控制,所以在使用中又有了一些轻量级的同步机制,例如vola ...

  8. 如何在高并发环境下设计出无锁的数据库操作(Java版本) 转载

    一个在线2k的游戏,每秒钟并发都吓死人.传统的hibernate直接插库基本上是不可行的.我就一步步推导出一个无锁的数据库操作. 1. 并发中如何无锁. 一个很简单的思路,把并发转化成为单线程.Jav ...

  9. .net 延时操作_锁、CAS操作和无锁队列的实现

    (给算法爱好者加星标,修炼编程内功) 来源:yishizuofei blog.csdn.net/yishizuofei/article/details/78353722 锁的机制 锁和人很像,有的人乐 ...

最新文章

  1. TensorFlow csv读取文件数据(代码实现)
  2. 目录页码错误未定义书签怎么解决_目录页码对不齐应该怎么办?这2种方法,工作效率大增...
  3. 耍了一下 UncaughtErrorEvents
  4. java 线程池 初始大小_为什么tomcat的默认线程池大小如此之大? - java
  5. Linux的标准I/O和管道
  6. android UI设计属性中英对照表(未修订)
  7. 美图个性化推荐的实践与探索
  8. [DappReview]2020年第一季度Dapp市场报告
  9. 系统架构师考试经验分享
  10. EasyClick易点云测 EC超级拓展插件laoleng.js
  11. 计算机 未保存,电脑突然关机wps没保存怎么办
  12. 软件测试带宽低,性能测试分析之带宽瓶颈的疑惑
  13. Bingo学习--redis
  14. java csrf 跨域_Django跨域请求CSRF的实例方法
  15. 电信增值短信平台模块清单(sp用)
  16. 知识管理对企业意味着什么
  17. [系统安全] 二.如何学好逆向分析及吕布传游戏逆向案例
  18. rosbag命令 | EVO工具 的使用
  19. nginx 负载均衡502问题
  20. 【XLL API 函数】xlCoerce

热门文章

  1. 10双屏鼠标过不去_灵耀X2 Duo双屏笔记本是怎样“炼”成的?对话华硕笔记本设计团队...
  2. JAVA语言运算符(算数运算符、赋值运算符、比较运算符、逻辑运算符、三元运算)
  3. 高可用MySQL MHA介绍
  4. 互联网日报 | 安邦保险集团将申请解散并清算;360中原总部落户郑州;英伟达400亿美元收购ARM...
  5. 所有的面试问题都可以归结为这三类(附回答套路)
  6. java http响应头,java – HTTP响应标头内容处理附件
  7. 界面设计方法 (2) — 3.卡式, 列表, 主细表, 树形, 页签
  8. 广州市城市智能交通大数据体系研究与实践
  9. 基于RDMA高速网络的高性能分布式系统
  10. 基于炼铁大数据智能互联平台推动传统工业转型升级