无锁队列实现原理_优先队列 java

无锁队列实现原理_优先队列 java首次接触无锁数据结构的设计,请各位大佬多多指教~~~CAS(Compare&&Swap)原子操作CAS是无锁(lockfree)的数据结构的基础。用伪代码描述:input:reg,old_val,new_val/*是old_val,reg替换为new_val,返回为true;否则返回为false*/if(*reg==old_val){*reg==new…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/198344.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • ASP.NET知识点总结[通俗易懂]

    ASP.NET知识点总结[通俗易懂]ASP.NET知识点总结1、ASP.Net的特色与优势2、几对概念3、解决方案构成4、系统对象与状态管理5、控件的分类6、站点地图7、系统导航8、母版页9、系统框架10、数据绑定11、数据源控件12、数据绑定控件GridView数据查询与展示、删除DetailsView展示多选光棒效果13、数据验证控件14、文件上载15、其他服务器控件DataList查询与展示16、基于SQL语句分页17…

    2022年7月11日
  • H3C路由器动态NAT配置步骤全解析

    H3C路由器动态NAT配置步骤全解析3C路由器所支持的动态NAT地址转换主要包括:NAPT、NOPAT、EASYIP这三种模式。一般情况下,通过在接口上配置所需关联的ACL和内部全局地址池(当采用EASYIP进行配置时不用配置址池)即可实现动态地址转换,让内部网络用户根据ACL(可选配置)所配置的策略动态选择地址池中可用的IP地址进行转换。但要注意:有些H3C设备还支持仅仅通过判断流出接口报文的源地址,而不使用ACL的方式来实现出接口报文的动态地址转换。

    2022年10月10日
  • 从几个常见需求看扫描电子书处理软件选择「建议收藏」

    从几个常见需求看扫描电子书处理软件选择「建议收藏」作者:马健邮箱:stronghorse_mj@hotmail.com发布:2020.01.04这几天在eshuyuan碰到一些人谈到扫描电子书处理,很多人的习惯是使用通用图像处理软件,包括Phot

    2022年8月1日
  • Git常用指令[通俗易懂]

    Git常用指令[通俗易懂]####gitclone远端地址 克隆到本地####gitpulloriginmaster 更新到本地####gitadd.####gitcommit-m"xxx"####gitpushoriginmaster 提交代码####gitbranch分支名称 创建分支####gitcheckout分支名 切换分支####gitbranch-D分支名; 彻底删除分…

    2022年5月29日
  • piggycase_java状态机设计

    piggycase_java状态机设计一、实验目的练习使用动态规划算法解决实际问题(使用Java语言实现)二、实验内容【问题描述】给定一个空存钱罐的重量和这个存钱罐最多能装进去的重量,现在需要在不打破这个存钱罐的情况下猜测里面最少的钱。每种钱的数量不做限制,条件是必须装满,同时给出每种钱币的价值和重量。【输入】输入的第一行数据包含整数T,表示测试用例的数量。每个测试用例的第一行都包含两个整数e和f(1<=e<=f<=10000),分别表示空存钱罐和装满硬币的存钱罐的重量(以克记)。第二行包含一个整数n(1&

    2022年11月3日
  • 金融投资理财基础知识

    金融投资理财基础知识随着当前金融互联网的兴起,当前的投资理财方式较以前相比,更加的多样化。就不说银行存款了,当下风险最低,收益最低的理财方式,因为通货膨胀,可能存的越久就钱越不值钱。下面主要介绍一下当下比较流行的投资方式: 一银行理财产品各个银行,无论是国有的,还是民营的银行,都有推出自己银行的理财产品。那什么是银行理财产品呢?就是银行开发设计并销售的资金投资和管理计划,银行只接受客户的授权管理资金

    2022年5月8日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号