当前位置: 首页 > 科技观察

让我们谈谈Interlocked.CompareExchange?

时间:2023-03-23 10:21:24 科技观察

Interlocked.CompareExchange的用法一直被说得很烂。为何再次被提及,主要看官网对其用途的描述。可能有些童鞋会比较迷惑。我们需要进一步消化它。说多了,一起来看看吧~~~说说什么时候用这个语法如题,这里...这里省略了一些词,上面的代码varlocation=1;varvalue=3;varcompared=1;Interlocked.比较交换(搬迁,价值,比较);如果原始值(location)与比较值(compared)一致,则用当前值(value)替换原始值。如上图,此时原始值为3。毫无疑问,我们非常清楚这是一个基本的使用问题。此语法可以比较基本类型和引用对象。官方在比较对象的时候也特此说明:对象比较的是引用相等,不是值相等。结果,相同值类型(例如,整数3)的两个装箱实例总是看起来不相等并且什么都不做。不要将此重载用于值类型。第一次看到的时候,没注意看的乱七八糟的。解释如下。从描述上看,有些童鞋会认为原值是空的,会导致空引用异常。下面的代码objecto1=null;object2=null;Interlocked.CompareExchange(refo1,o2,null);运行上面的代码不会抛出空引用异常。为什么?官方解释错了吗?不会有任何疑问。官方的解释是空指针(notnull),但是我们的代码是空引用。有了空引用,那我们是不是可以认为一定不能抛出空引用异常呢?官方的解释是空指针和null不是一个概念。这样的解释很容易造成概念上的混淆。还是去掉比较好,好像有点多余再想想,也不是那么绝对。我个人认为至少在托管的情况下,理论上应该不会抛出异常。在非托管的情况下可能无法保证,或者通过IL操作底层,也会触发上述的空引用异常。总结个人理解,官方的解释并没有混淆,但是好像造成了概念上的混淆,让部分童鞋认为不能传空值,希望没有误导大家。那么在哪些场景下我们会使用上面的原始值为空呢?例如,确保对象被初始化,如下所示:完全初始化,如下:;Console.WriteLine(result==null);Console.WriteLine(target);returntarget!;}当上面的方法返回一个对象实例时,我们用C#8.0语法表明对象实例永远不能为空。此语法有一个返回值。打印出来的结果和替换后的原值一样吗?不是,除了替换原值外,对于所有情况,返回值都是原来的原值,这是旧的据我所知,语法底层直接操作CPU处理器指令,当然是一个原子操作。甚至操作系统也不能执行中断操作。线程可以在指令执行前被抢占,但在指令执行过程中不会被抢占。也就是说,绝对不会出现当原值和比较值相等的时候,另一个线程指令根据上面的理论改变了原值,所以网上大部分都是通过循环的方式将最新的原值赋给返回结果实现的并发无锁修改操作publicstaticAddressEnsureAddressInitialized(refAddresstarget,Orderorder,Funcfunc){if(target!=null){returntarget;}while(Interlocked.CompareExchange(reftarget,func(order),null)==null){break;}returntarget;}为了避免上述不必要的循环操作,也为了避免CPU缓存,我们进一步优化了代码,通过使用Volatile关键字获取内存中最新存储的数据,以及最终演变成如下,空);返回目标!;}概念混淆可能会导致使用上的疑惑,同时我们基于理论逐步优化,实现并发无锁修改操作