首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Interlocked.Exchange澄清

Interlocked.Exchange澄清
EN

Stack Overflow用户
提问于 2012-10-22 22:27:56
回答 3查看 3.3K关注 0票数 3

我有几个简单的(希望是)问题,我一直无法找到答案-

假设我有多个线程可以访问的对象a,b。

代码语言:javascript
复制
Interlocked.Exchange(ref a, b)

如果'b‘不是易失性的,此操作是否会将其视为易失性?也就是说,它会从内存中获取这个变量的最新值吗?如果是,那么读写是“原子”吗?我知道Interlocked.Exchange的主要目的是让你在新的写操作中得到之前的'a‘值作为一个原子操作。但我最大的困惑是,“b”的值实际上写成了“a”。

我的第二个问题与本文中的一句话有关:

http://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/

“有趣的一点是,根据这里和这里介绍的内存模型,C#中的所有写入都是易失性的,并且也可能是这样实现的。C#语言的ECMA规范实际上定义了一个较弱的模型,其中写入在默认情况下不是易失性的。”

这是真的吗?如果是这样,如果一个人不关心'a‘的前一个值,那么Interlocked.Exchange还有什么用处吗?(与我的第一个示例相关)。我没有在StackOverflow上看到任何其他的文章或评论,每一篇文章都是不稳定的。然而,我知道写是原子的。

编辑:如果我的第一个问题的答案是'b‘不被视为易失性,而我的第二个问题的答案是写确实是易失性的,那么后续的问题是,如果我们不关心'a’的前一个值,那么interlocked.exhange什么时候有用?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-10-22 22:46:57

传递给Exchange的变量(或传递给任何方法的任何易失性变量)在传递时不会保留“易失性”...实际上没有必要让它成为volatile (在方法调用期间),因为volatile所做的唯一一件事就是确保编译器不会优化变量的使用(这通常意味着优化对寄存器的写入,这样值就只能被单个处理器“看到”)。在x86/x64以外的处理器上,这有时意味着保证获取或释放语义的指令。.NET不使用寄存器传递参数,因此易失性不会影响传递的参数的“波动性”。由于内存模型的可见性保证,它必须始终从内存中获取最新的值

回复问题2:引用是“某种”正确的,取决于字段的声明,有可见性保证w.r.t。字段;但没有“易失性”字段访问可以在使用的某些阶段优化到寄存器中,潜在地对其他处理器隐藏某些写操作。

Interlocked交换使非原子的操作看起来像原子的。Exchange本质上类似于:

代码语言:javascript
复制
var x = someVariable;
someVariable = y;

无论someVariable的类型如何,这都不能是原子的。Exchange使此操作成为原子操作。这也是具有非原子类型的原子类型,如doublelong (32位)等。

Exchange为实现这种原子化所做的部分工作就是使用内存栅栏--它使写操作可见,并且不会在内存栅栏之后的指令序列中对相同内存地址的读取重新排序。

如果你不关心'a‘的前一个值,为什么要使用Exchange呢?如果您不关心实际的“交换”,那么VolatileWrite似乎更合适。

或者,如果不需要“交换”,您可以编写线程安全代码来建模"A=B“,如下所示:

代码语言:javascript
复制
Thread.MemoryBarrier();
A=B;

在一些处理器中,Interlocked部分是围绕比较和交换(CAS)指令进行建模的。这些指令允许您在一条指令中完成这两个操作(使其成为原子指令)。如果没有像Interlocked这样的东西,编译器可能很难推断出应该使用这些CAS指令中的一个。此外,Interlocked在不支持这些CAS指令的处理器上提供原子使用(以及其他潜在的非原子指令,如inc和dec--并非所有处理器都可用)

票数 7
EN

Stack Overflow用户

发布于 2012-10-22 22:36:08

如果'b‘不是易失性的,此操作是否会将其视为易失性?

b是一个共享变量时,我认为你不应该使用它。所以这就消除了整个问题。但Exchange将始终使用内存屏障,因此答案可能是肯定的。

如果我们不关心'a‘的前一个值,

什么时候interlocked.exhange有用?

double的重载非常有用,因为在其他情况下,对double的写入不是原子的。32位系统上的Int64也是如此。

但是对于原子类型上的Exchange()重载,用例就不那么清晰了。我认为大多数算法都会偏爱CompareExcange()

因此,可以将其视为原子Write()。

票数 1
EN

Stack Overflow用户

发布于 2012-10-22 22:37:58

如果'b‘不是易失性的,此操作是否会将其视为易失性?

是的,因为根据this sourceInterlocked类的所有方法都会生成隐式内存围栏。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13013555

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档