gpt4 book ai didi

c# - Interlocked.Exchange 说明

转载 作者:行者123 更新时间:2023-11-30 13:48:18 28 4
gpt4 key购买 nike

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

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

Interlocked.Exchange(ref a, b)

如果“b”不是 volatile 的,这个操作会这样对待它吗?即它会从内存中获取这个变量的最新值吗?如果是这样,那是用写读“原子”吗?我知道 Interlocked.Exchange 的主要目的是您将获得 'a' 的先前值作为新写入的原子操作。但我的主要困惑在于“b”的值实际写入了“a”。

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

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

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

这是真的吗?如果是这样,如果不关心“a”的先前值,是否存在 Interlocked.Exchange 的目的? (关于我的第一个例子)。我没有在 StackOverflow 上看到关于每次写入都不稳定的任何其他文章或评论。但是,我知道写入是原子的。

编辑:如果我的第一个问题的答案是“b”不被视为易变的,而我的第二个问题的答案是写入确实是易变的,那么后续问题是,interlocked.exhange 何时有用,如果我们不关心 'a' 的先前值?

最佳答案

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

RE 问题 2:引用“有点”是真的,这取决于字段的声明,有可见性保证 w.r.t.字段;但如果没有“ volatile ”字段访问,则可以在某些使用阶段将其优化为寄存器,从而可能对其他处理器隐藏某些写入。

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

var x = someVariable;
someVariable = y;

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

Exchange 为实现原子性所做的部分工作是使用内存栅栏——这使得写入可见,并且不会与内存之后的指令序列中相同内存地址的读取重新排序围栏。

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

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

Thread.MemoryBarrier();
A=B;

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

关于c# - Interlocked.Exchange 说明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13013555/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com