C# 交换澄清

C# 交换澄清,c#,multithreading,.net-4.0,interlocked,C#,Multithreading,.net 4.0,Interlocked,我有几个简单(希望如此)的问题,我一直无法找到答案- 假设我有多个线程可以访问的对象a、b Interlocked.Exchange(ref a, b) 如果“b”不是易失性的,此操作会将其视为易失性吗?i、 e.是否从内存中获取该变量的最新值?如果是这样,读和写是“原子的”吗?我知道interlocted.Exchange的主要目的是,您将通过新的写入操作获得以前的原子操作值'a'。但我的主要困惑是“b”的值实际上是写在“a”上的 我的第二个问题与本文中的一句话有关: “有趣的一点是,根据

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

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

Interlocked.Exchange(ref a, b)
如果“b”不是易失性的,此操作会将其视为易失性吗?i、 e.是否从内存中获取该变量的最新值?如果是这样,读和写是“原子的”吗?我知道interlocted.Exchange的主要目的是,您将通过新的写入操作获得以前的原子操作值'a'。但我的主要困惑是“b”的值实际上是写在“a”上的

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

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

这是真的吗?如果是这样的话,如果不关心“a”之前的值,是否有联锁交换的目的?(关于我的第一个例子)。我看不到关于StackOverflow的任何其他文章或评论都是不稳定的。然而,我知道写是原子的

编辑:如果我的第一个问题的答案是“b”不被视为易失性,而我的第二个问题的答案是写入确实是易失性的,那么后续是,何时是互锁的。如果我们不关心之前的“a”值,那么呼气有用吗

如果“b”不是易失性的,此操作会将其视为易失性吗

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

如果我们不关心“a”的前一个值,when是interlocked.exhange有用吗

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

但是对于原子类型上的
Exchange()
重载,用例就不那么清楚了。我认为大多数算法都支持
compareexchange()

请考虑原子写() 如果“b”不是易失性的,此操作会将其视为易失性吗


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

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

关于问题2:引用是“某种程度上”正确的,取决于字段的声明,存在w.r.t.字段的可见性保证;但如果没有“易失性”,字段访问可以在特定的使用阶段优化到寄存器中,从而可能对其他处理器隐藏某些写入

互锁
交换使非原子操作看起来像原子操作。交换性质类似于:

var x = someVariable;
someVariable = y;
无论
someVariable
的类型如何,它都不能是原子的<代码>交换
使此操作原子化。对于非原子类型,如
double
long
(32位)等,这也是原子的

Exchange
使这个原子化的部分功能是使用内存围栏——它使写操作可见,并且不会在内存围栏之后的指令序列中,对相同内存地址的读取进行重新排序

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

或者,如果不需要“exchange”,您可以按如下方式将线程安全代码写入模型“A=B”:

Thread.MemoryBarrier();
A=B;

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

b的“波动性”应该无关紧要。谢谢。这是否也意味着读取B的值是原子的,而将该值写入A?或者,在分配给A之前,B的值在技术上仍然可以更改吗?@user981225:Well
B
是按值传递给方法的,因此方法调用后的任何更改都不会干扰方法接收到的值。谢谢。你能解释一下为什么当b是一个共享变量时你不认为应该使用它吗?把它转过来:什么时候/为什么你要把一个共享的b写到一个共享的a?这样说很有道理:)谢谢你的回答。w、 r.t您的问题是,如果您不关心a的前一个值,为什么要使用exchange?如果B不是易变的,但我们希望确保我们没有将a设置为缓存的B值,该怎么办?如果问题2只是“某种程度上”正确的话,那么这样设置一个参数是否可能与se不同呢