聊聊Interlocked.CompareExchange吧?

【导读】私下空余时间一直在研究开源框架,当然也就少不了学习优秀源码,本文也是我查看有关源码时,触碰到我个人知识盲区,做此记录,分享下

Interlocked.CompareExchange这玩意用法被讲的很烂了,为何再次被提及,主要看了下官网对其使用描述可能对于部分童鞋来讲具备一定迷惑性,需我们进一步消化下,话不多讲,我们来看看吧~~~

浅谈如标题

关于啥时候用此语法,这.....此处省略若干字,上代码

var location = 1;var value = 3;var compared = 1;Interlocked.CompareExchange(ref location, value, compared);

若原始值(location)与比较值(compared)一致,则将当前值(value)替换原始值。如图上述,此时原始值将为3,毫无疑问,我们很清楚这是基本用法

问题来了,该语法既可比较基本类型也可比较引用类型

当比较对象时,官方还特此备注注意:

比较对象的引用相等性,而不是值相等性。结果,两个具有相同值类型(例如,整数3)的装箱实例始终看起来不相等,并且不执行任何操作。不要将此重载用于值类型。


初次看,稍不注意的迷惑性来了,解释如下截图

从描述上看,一部分童鞋是不是会认为,原始值为空,则会引发空引用异常,如下代码

object o1 = null;object o2 = null;Interlocked.CompareExchange(ref o1, o2, null);

运行上述代码将不会抛出空引用异常,这是为何?难道官方解释有误,接下来我们深入探讨下

深谈如标题

若对C语言有所了解,则不会存在疑惑,官方解释为空指针(不是空),而我们代码是空引用,二者不可同日而语

C#中对于引用类型,定义现有的变量必将存在引用,所以在C#中不可能存在空引用,所以我们是不是可以认为必然不会存在抛出空引用异常

官方解释为空指针和null其实并不是同一个概念,如此一解释,极易引起概念混淆,还不如去掉,显得有点多余

再想想,也不是那么绝对,个人以为,至少在托管情况下理论上应该不会抛出任何异常,非托管情况下可能没有保证,或者通过IL操作底层,也会触发上述空引用异常

综上个人理解,官方解释谈不上迷惑性,只是好像有点会引起概念混淆,让部分童鞋以为不能传递空,希望没将各位绕晕

那么我们在哪些场景下会用到上述原始值为空的情况呢?比如确保对象初始化,如下:

public class Order
{public Address Address{get{return CreateAddress();}}private Address CreateAddress() => new Address();
}public class Address
{
}

当我们在Order内部使用Address时,确保其实例已完全初始化,如下:

static Address EnsureAddressInitialized()
{var order = new Order();Func<Order, Address> func = f => f.Address;Address target = null;var result = Interlocked.CompareExchange(ref target, func(order), null);Console.WriteLine(result == null);Console.WriteLine(target);return target!;
}

上述方法返回对象实例时,我们使用C# 8.0语法表明对象实例绝不可能为空

该语法有返回值,那打印结果是否和替换后的原始值一样呢?不是,除了替换原始值外,针对所有情况,返回值都是最初原始值即旧值。

据我所知,该语法底层直接操作CPU处理器指令,当然也是原子性操作,即便是操作系统也无法执行中断操作,线程可以在指令执行之前被抢占,但在指令执行期间不会被抢占,换言之,绝不会出现,当原始值和比较值比较相等时,而另一线程指令更改原始值的情况

基于上述理论,所以才有了网上大多数通过循环方式对其返回结果赋最新原始值实现并发无锁修改操作

public static Address EnsureAddressInitialized(ref Address target,Order order, Func<Order, Address> func){if (target != null){return target;}while (Interlocked.CompareExchange(ref target, func(order), null) == null){break;}return target;}

为避免上述没必要的循环操作,同时也为避开CPU缓存,我们进一步进行代码优化,通过使用Volatile关键字获取内存最新存储数据,最终演变成如下这般

public static Address EnsureAddressInitialized(ref Address target,Order order, Func<Order, Address> func)
{var tmp = Volatile.Read(ref target);if (tmp != null){return tmp;}Interlocked.CompareExchange(ref target, func(order), null);return target!;
}

???? 概念的混淆可能会存在使用上的疑惑,同时我们基于理论逐步优化,实现并发无锁修改操作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/305321.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

winform 统计大量数据重复的元素个数_面试系列:十个海量数据处理方法大总结...

本文将简单总结下一些处理海量数据问题的常见方法。当然这些方法可能并不能完全覆盖所有的问题&#xff0c;但是这样的一些方法也基本可以处理绝大多数遇到的问题。下面的一些问题基本直接来源于公司的面试笔试题目&#xff0c;方法不一定最优&#xff0c;如果你有更好的处理方…

java 堆栈_Java中线程与堆栈的关系

栈是线程私有的&#xff0c;每个线程都是自己的栈&#xff0c;每个线程中的每个方法在执行的同时会创建一个栈帧用于存局部变量表、操作数栈、动态链接、方法返回地址等信息。每一个方法从调用到执行完毕的过程&#xff0c;就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。其…

java怎么将前端的数据存到关联的表中_Java程序员最可能被考到的14个面试题

1. 如何只扫描一遍就找到位于一个链表正中间的元素&#xff1f; 这是最受欢迎的算法题之一&#xff0c;经常在电话面试中被问到。很多程序员会想&#xff0c;要知道链表的长度&#xff0c;就要先扫描一遍链表&#xff0c;然后在第二遍中取其正中的元素。所以被要求只扫描一遍就…

常见的几种最优化方法

阅读目录1. 梯度下降法&#xff08;Gradient Descent&#xff09;2. 牛顿法和拟牛顿法&#xff08;Newtons method & Quasi-Newton Methods&#xff09;3. 共轭梯度法&#xff08;Conjugate Gradient&#xff09;4. 启发式优化方法我们每个人都会在我们的生活或者工作中遇到…

专业的软件安装包可以这样做!

C/S客户端开发完成&#xff0c;需要将程序交付给用户&#xff0c;直接压缩发给用户是可以的&#xff08;只是有点不专业&#xff09;&#xff0c;如果能有一个比较好看的安装界面&#xff0c;那档次就不一样了。本文介绍怎么使用Adanced Installer 17.9 制作专业的Windows 客户…

IT人喝酒,不同岗位不同姿势

这是Boss们的常用套路&#xff0c;频频举杯&#xff0c;给大家鼓劲加油&#xff0c;但是自己不喝。有的销售&#xff0c;业绩好&#xff0c;酒品也好&#xff0c;不管和自己人喝酒&#xff0c;还是和客户喝酒&#xff0c;都是一副舍我其谁的霸气&#xff01;这是某些销售的写照…

国产CPU群雄逐鹿谁主沉浮

当下&#xff0c;国内&#xff08;桌面、服务器&#xff09;CPU与外商有较大差距&#xff0c;除了海光在性能上可能具有一拼之力外&#xff0c;其它国产CPU在商业市场上面对英特尔、AMD基本不具备竞争力&#xff0c;因而只能在篱笆墙内的市场角逐。而为了能够进入篱笆墙内的市场…

蒙特卡罗方法入门

本文通过五个例子&#xff0c;介绍蒙特卡罗方法&#xff08;Monte Carlo Method&#xff09;。一、概述蒙特卡罗方法是一种计算方法。原理是通过大量随机样本&#xff0c;去了解一个系统&#xff0c;进而得到所要计算的值。它非常强大和灵活&#xff0c;又相当简单易懂&#xf…

面向业务的微服务消息总线

源宝导读&#xff1a;移动PaaS项目的异步场景中&#xff0c;随着订阅主题数的增加&#xff0c;会出现开发维护成本高、管理难度大等问题&#xff0c;本文将分享如何通过构建面向业务的微服务消息总线应对这些问题。一、背景面向业务的消息总线本质上是对消息队列进行二次封装&a…

模拟时钟中断的产生及设计一个对时钟中断事件进行处理的模拟程序_操作系统基础6-支持操作系统的最基本的硬件-中断...

无论是桌面PC操作系统还是嵌入式都是多任务的操作系统&#xff0c;而很遗憾&#xff0c;处理器往往是单个的&#xff0c;即便在硬件成本逐渐下降&#xff0c;而硬件配置直线上升的今天&#xff0c;PC机的核心可能已经达到&#xff14;核心&#xff0c;&#xff18;核心&#xf…

XMLhttp学习应用

Client.htm页面代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns"http://www.w3.org/1999/xhtml"><head><title>客…

机器学习没有想象中的那么难

文末彩蛋&#xff0c;不容错过&#xff01;背景从去年的AlphaGo到今年人工智能首次写进政府工作报告&#xff0c;人工智能正在席卷全球&#xff0c;引发第4次工业革命&#xff0c;而AI的核心技术是机器学习和深度学习。目前&#xff0c;机器学习已广泛应用于数据挖掘、计算机视…

Docker查看应用的实际内存

前言 我们把应用部署到Docker里面之后&#xff0c;有什么办法查看这个应用占用了多少内存呢&#xff1f;docker本身提供了一个命令让我们可以直接看到当前时间所有容易占用的情况。docker stats --no-stream从上面来看&#xff0c;这几个应用用的内存加起来已经是将近12G了。但…

如何动态的生成某种类型的集合呢_知乎画报」的移动端动态化工程实践

本文基于移动端动态化方案在知乎原生推广落地页「知乎画报」上的实践经验&#xff0c;对该方案技术升级过程中的思考以及技术关键细节做了详尽的解读。商业化是互联网公司发展的重要阶段&#xff0c;App 端的商业广告业务对移动端动态化能力的需求很强烈&#xff0c;一方面需要…

任正非致歉华为前程序员:回来吧,公司错了

近几日&#xff0c;因着任正非连续签发邮件&#xff0c;无处不在热议华为&#xff0c;其中与所有的技术人可谓密切相关。除了一员工因说真话&#xff0c;被晋升两级&#xff0c;根据其自愿选择工作岗位及地点&#xff0c;并由无线网络产品线总裁邓泰华保护其不受打击报复之外&a…

Asp.Net Core之Identity应用(下篇)

一、前言在上篇中简单介绍了 Asp.Net Core 自带的 Identity,一个负责对用户的身份进行认证的框架&#xff0c;当我们按需选择这个框架作为管理和存储我们应用中的用户账号数据的时候&#xff0c;就会添加到自己的项目当中去。这个时候&#xff0c;默认情况我们会使用自带的数据…

如果每一种语言都对应一种女生,你会喜欢哪一个?

这几天调试都很顺利&#xff0c;今天很意外的不要加班&#xff0c;哥几个看着窗外还是白天&#xff0c;还有点不适应。没想到哥几个突然开始YY&#xff1a;如果每种语言都对应一种女生&#xff0c;你会喜欢哪一个&#xff1f;程序猿寂寞起来&#xff0c;我自己都害怕。碍于人数…

asp.net core安全事项(下)

越权越权是非常严重的安全漏洞&#xff0c;通常状态是开发人员对请求的限制逻辑不严格导致的。如果系统中有角色的概念&#xff0c;越权可能出现不同角色间的越权和同角色间的越权。相同角色&#xff1a;A用户&#xff0c;B用户是相同的角色。A用户和B用户都可以调用 /photo/{i…

[导入]php 安全基础 第八章 共享主机 文件系统浏览

8.4. 文件系统浏览 除了能在共享服务器上读取任意文件之外&#xff0c;攻击者还能建立一个可以浏览文件系统的脚本。由于你的大多数敏感文件不会保存在网站主目录下&#xff0c;此类脚本一般用于找到你的源文件的所在位置。请看下例&#xff1a; <pre> <?php if (iss…