首次接触无锁数据结构的设计,请各位大佬多多指教~~~

CAS(Compare && Swap)原子操作

CAS是无锁(lock free)的数据结构的基础。用伪代码描述:

input: reg, old_val, new_val

/*是old_val, reg替换为new_val,返回为true;否则返回为false*/

if (* reg == old_val) {

* reg == new_val;

return true;

} else {

return false;

}

CAS相似的原子操作:

fetch and add,一般用来对变量做+1的原子操作

test and set, 写值到内存位置并传回其旧值

test test and set : 和双检查锁一样为了减少对锁的多次竞争,对锁的竞争代价比普通判断锁的状态要大,这里需要着重强调,在high level programming的背景下,尽量少用双重检测锁的形式,因为第二次检查和设置并不一定是原子操作。test test and set伪代码(Wikipedia test test and set)如下:

boolean locked := false // shared lock variable

procedure EnterCritical() {

do {

while (locked == true) skip // spin until lock seems free

} while TestAndSet(locked) // actual atomic locking, this cost of step >> the cost above !!!;

}

在此稍微记录一下,

GCC的原子CAS的API

bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)

type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...)

C++11的CAS

C++11的STL中的atomic类的函数可以跨平台。

template< class T >

bool atomic_compare_exchange_weak( std::atomic* obj,

T* expected, T desired );

template< class T >

bool atomic_compare_exchange_weak( volatile std::atomic* obj,

T* expected, T desired );

无锁队列的链表实现

EnQueue(x) {

// 准备新加入的结点数据

q = new record();

q->value = x;

q->next = NULL;

do {

p = tail; // 链表尾指针的快照

} while( CAS(p->next, NULL, q)!= true)

CAS(tail, p, q);

}

do while的Re-Try-Loop,如果别的进程已经加成功了,tail就变了,p!=tail, p->next!= NULL,那么就重试。

这里存在一个问题,如果在CAS(tail, p, q)之前线程挂掉了或者停掉了,其它线程更新了p->next,却没有更新tail,然后就一直进入死循环。为了解决这个问题,下面推出了改良版的EnQueue()

EnQueue(x)

{

q = new record();

q->value = x;

q->next = NULL;

p = tail;

oldp = p;

do {

while (p->next!= NULL) {

p = p->next;

} while (CAS(p->next, NULL, q)!= TRUE); // 如果没有把结点链在尾上,再试

CAS (tail , oldp, q); // 置尾结点

}

}

fetch会很影响性能, 所以可以结合以上两个版本,如果retry的次数超过一个阈值,那么自己就fetch指针。

但是这里存在一个问题,就oldq能不能及时更新,若不能及时更新,其余线程在插入时会插到未定义的位置。个人觉得还是选择未改良版比较好。

DeQueue // 出队列

DeQueue() {

do {

p = head;

if (p -> next == NULL) {

return ERR_EMPTY_QUEUE;

}

} while ( CAS(head, p, p->next)!= TRUE);

return p->next->value;

}

CAS的ABA问题:

进程p1在共享变量中读到值为A

p1被抢占了,进程p2执行

p2把共享变量里的值从A改成B,再改回到A,此时被p1抢占。

p1回来看到共享变量里的值没有被改变,于是继续执行。

看来好像没有问题,但是上式的CAS其实判断的是指针地址,然而指针内容改变了,不就炸了?这就是内存管理中的重用内存问题。

解决ABA的问题

例如在32位系统上检查64位的内容:

一次用CAS检查双倍长度的值,前半部分是指针,后半部分是一个计数器

只有这两个都一样,才算通过,要用该指针符新的值,计数器加1。

这种方法线程次数上应该也没问题,但是一旦多了,可能会溢出循环计数。

所以有论文提出了使用结点内存的引用计数,这和智能指针没啥区别嘛,但是需要保证加引用计数和减引用计数为原子操作。

用数组实现无锁队列

无锁队列可以用ring buffer实现,定位head和tail可以声明两个计数器,一个用来计数EnQueue的次数,一个用来计数DeQueue的次数,当队列满或空,可以抛出异常,没有内存泄露的问题。

reference

无锁队列 java_无锁队列的总结相关推荐

  1. 悲观锁代码java_悲观锁的代码实现如何编写?

    悲观锁相信大家都不陌生了,之前说过了悲观锁的各种原理,这次我们就来聊聊悲观锁是如何实现的吧. 悲观锁,就跟它的名字意思一样,它非常悲观,它的机制就是对数据被外界(包括本系统当前的其他事务,以及来自外部 ...

  2. 无ide编译java_无IDE编译和运行java

    建立和运行Java代码 为了对这篇文章进行更具体的讨论,我将使用一些非常简单的Java类,在同一个包中通过彼此相关的组合或继承(不在 未命名的包中)来调用dustin.examples.这两个在第三个 ...

  3. 队列加锁无锁栈实现一例

    本篇文章个人在上海游玩的时候突然想到的...这两天就有想写几篇关于队列加锁的笔记,所以回家到之后就奋笔疾书的写出来发布了 一.何谓无锁队列 无锁队列,望文生义,即不需要加锁的队列:之所以不需要额定加锁 ...

  4. 无锁队列与有锁队列性能比较

    最近研究boost的无锁队列,测试了一下性能,发现无锁队列比有锁的还要慢 testqueue.cpp #include <time.h> #include <boost/thread ...

  5. 无锁CAS及无锁队列实现

    CAS ⽐较并交换(compare and swap, CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据 交换操作,从⽽避免多线程同时改写某⼀数据时由于执⾏顺序不确定性以及中断的不可 ...

  6. java 无锁栈_队列加锁无锁栈实现一例

    本篇文章个人在上海游玩的时候突然想到的...这两天就有想写几篇关于队列加锁的笔记,所以回家到之后就奋笔疾书的写出来发布了 一.何谓无锁队列 无锁队列,望文生义,即不需要加锁的队列:之所以不需要额定加锁 ...

  7. 无锁编程与有锁编程的效率总结、无锁队列的实现(c语言)

    1.无锁编程与有锁编程的效率 无锁编程,即通过CAS原子操作去控制线程的同步.如果你还不知道什么使CAS原子操作,建议先去查看相关资料,这一方面的资料网络上有很多. CAS实现的是硬件级的互斥,在线程 ...

  8. java的“看门狗”锁续期可以用php redis这样实现【php锁续期、分布式锁、无锁请求队列超卖】解决【商家超卖(商品库存控制)、用户超买(秒杀订单控制)】问题。非demo 线上一直在用

    要求与痛点描述 1.不允许使用库存创建队列 因为库存如果是10w难道要创建一个10w长度的队列吗 2.不允许对整个业务过程加锁 可能业务执行时间很长 导致锁粒度太大 影响并发量 3.如果业务时间大于锁 ...

  9. java8 同步队列_秋招之路8:JAVA锁体系和AQS抽象队列同步器

    整个的体系图 悲观锁,乐观锁 是一个广义概念:体现的是看待线程同步的不同角度. 悲观锁 认为在自己使用数据的时候一定有别的线程来修改数据,在获取数据的时候会先加锁,确保数据不被别的线程修改. 实现:关 ...

最新文章

  1. hashcode的作用_看似简单的hashCode和equals面试题,竟然有这么多坑!
  2. 借助URLOS快速安装python3网站环境
  3. ABAP如何检查字符串是否为日期或时间格式
  4. 网上一个仿TP挂钩内核的源码
  5. Linux系统编程---5(共享存储映射,存储映射I/O,mmap函数,父子进程间通信,匿名映射)
  6. C++工作笔记-map中结构体的比较
  7. Mybatis mapper代理Dao开发
  8. toolbox、library 的组织
  9. Kettle parameter方式实现循环
  10. Swift 周报 第十期
  11. 魔兽单机80mysql创建账号_本站魔兽世界单机版如何注册账号及局域网架设 | 游戏海湾...
  12. 深度学习(花书)+ 动手学深度学习(李沐)资料链接整理
  13. Cannot execute binary file 之原因
  14. 240天,转行程序员终于成为CSDN博客专家
  15. 融合办公时代来了?联想Filez带你正确解读“融合办公”新模式
  16. Excel-VBA操作文件四大方法之一(转)
  17. rageframe(PHP微擎)树分类(curd)
  18. forgot XCTF(你的疑问都可以在这里找到答案)
  19. VDI序曲十 ThinPC安装体验
  20. Delphi TStringGrid 类(1)

热门文章

  1. JAVA毕设项目漫画网站系统(java+VUE+Mybatis+Maven+Mysql)
  2. EXCEL 2007施工进度横道图制作步骤及实战练习
  3. 安装Ubuntu+gpu+tensorflow+py2+py3
  4. (85)如何编写仿真激励?
  5. java框架ssm_【Java】SSM框架整合 附源码
  6. iphone录屏在哪里打开?手机上有哪些录制的方法
  7. Oracle数据库之查询排序
  8. H264 获取SPS与PPS
  9. windows系统 -快捷键
  10. Linux Running State Process .so、code Injection Technology