简体   繁体   English

Interlocked.Exchange澄清

[英]Interlocked.Exchange clarification

I have a few simple (hopefully) questions that I have been unable to find answers for - 我有一些简单(希望)的问题,我一直无法找到答案 -

Say I have objects a, b that are accessible to multiple threads. 假设我有多个线程可以访问的对象a,b。

Interlocked.Exchange(ref a, b)

If 'b' is not volatile, will this operation treat it as such? 如果'b'不是易变的,这个操作会不会这样处理? ie will it take the latest value of this variable from memory? 即它会从内存中获取此变量的最新值吗? If so, is that read 'atomic' with the write? 如果是这样,那写入是'原子'吗? I understand that the main purpose of Interlocked.Exchange is that you will get the previous value of 'a' as an atomic operation with the new write. 据我所知,Interlocked.Exchange的主要目的是使用新写入将原来的'a'值作为原子操作。 But my main confusion is around what value of 'b' is actually written to 'a'. 但我的主要困惑在于'b'实际写入'a'的价值。

My second question is related to a quote in this article: 我的第二个问题与本文中的引用有关:

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

"One interesting point is that all writes in C# are volatile according to the memory model as documented here and here, and are also presumably implemented as such. The ECMA specification of the C# language actually defines a weaker model where writes are not volatile by default." “一个有趣的观点是C#中的所有写操作都是根据本文和此处记录的内存模型进行的,并且也可能是这样实现的.C#语言的ECMA规范实际上定义了一个较弱的模型,其中写入默认情况下不是易失性的“。

Is this true? 这是真的? If so, is there a purpose of Interlocked.Exchange if one doesn't care about the previous value of 'a'? 如果是这样,如果不关心'a'的先前值,是否有Interlocked.Exchange的目的? (pertaining to my first example). (与我的第一个例子有关)。 I don't see any other articles or comments on StackOverflow around every write being volatile. 我没有在StackOverflow上看到任何关于每个写入易失性的文章或评论。 I understand, however, that writes are atomic. 但是,我知道写入是原子的。

Edit: If the answer to my first question is that 'b' is not treated as volatile, and the answer to my second question is that writes are indeed volatile, then a follow up is, when is interlocked.exhange useful if we don't care about the previous value of 'a'? 编辑:如果我的第一个问题的答案是“b”不被视为易失性,而我的第二个问题的答案是写入确实是不稳定的,那么跟进就是,什么时候是联锁的。如果我们不这样做,则有用关心'a'的先前价值?

the variable passed to Exchange (or any volatile variable passed to any method) does not retain "volatility" when passed... There's actually no need for it to be volatile (for the duration of the method call) because the only thing that volatile does is to make sure that the compiler(s) do not optimize use of the variable (which generally means optimizing writes into registers so the value can only be "seen" by a single processor). 传递给Exchange的变量(或传递给任何方法的任何volatile变量)在传递时不会保留“volatile”...实际上不需要它是volatile (在方法调用期间)因为唯一的volatile确保编译器不优化变量的使用(这通常意味着优化写入寄存器,因此值只能由单个处理器“看到”)。 On processors other than x86/x64, this sometimes means instructions that guarantee acquire or release semantics. 在x86 / x64以外的处理器上,这有时意味着保证获取或释放语义的指令。 .NET doesn't use registers for argument passing, so volatile couldn't affect "volatility" of the arguments passed. .NET不使用寄存器进行参数传递,因此volatile不会影响传递的参数的“波动性”。 It has to always get the latest value from memory due to visibility guarantees of the memory model 由于内存模型的可见性保证,它必须始终从内存中获取最新值

RE question 2: the quote is "sort of" true, depending on the declaration of a field, there are visibility guarantees wrt fields; RE问题2:引用是“真实的”,取决于字段的声明,有可见性保证wrt字段; but without "volatile" field access can be optimized into a register in certain phases of use, potentially hiding certain writes from other processors. 但是没有“volatile”字段访问可以在某些使用阶段被优化到寄存器中,可能隐藏来自其他处理器的某些写入。

Interlocked exchanges make operations that were not atomic appear atomic. Interlocked交换使非原子的操作看起来是原子的。 Exchange by nature is similar to: 交换本质上类似于:

var x = someVariable;
someVariable = y;

This cannot be atomic regardless of the type of someVariable . 无论someVariable的类型如何,这都不可能是原子的。 Exchange makes this operation atomic. Exchange使此操作成为原子。 This is also atomic with non-atomic types like double , long (in 32-bit), etc. 这也是非原子类型的原子,如doublelong (32位)等。

Part of what Exchange does to make this atomic is to use memory fences--which make writes visible and not re-ordered with reads of the same memory address in the sequence of instructions after the memory fence. Exchange使用这个原子的部分原因是使用内存栅栏 - 这使得写入可见而不是重新排序,并且在内存栅栏之后的指令序列中读取相同的内存地址。

Why would you use Exchange if you don't care about the previous value of 'a'? 如果您不关心“a”的先前值,为什么要使用Exchange If you don't care about an actual "exchange", then VolatileWrite seems more appropriate. 如果你不关心实际的“交换”,那么VolatileWrite似乎更合适。

Alternatively, if "exchange" is not needed, you could write thread-safe code to model "A=B" as follows: 或者,如果不需要“交换”,您可以编写线程安全代码来模拟“A = B”,如下所示:

Thread.MemoryBarrier();
A=B;

FWIW, Interlocked is partially modelled around compare-and-swap (CAS) instructions in some processors. FWIW, Interlocked部分模拟了某些处理器中的比较和交换(CAS)指令。 These instructions allow you to do these two operations in one instruction (making it atomic). 这些指令允许您在一条指令中执行这两项操作(使其成为原子)。 Without things like Interlocked it could be difficult for a compiler to infer that one of these CAS instruction should be used . 如果没有像Interlocked这样的东西,编译器可能很难推断出应该使用这些CAS指令之一。 In addition, Interlocked provides atomic usage on processors that don't support these CAS instructions (and other potentially non-atomic instructions like inc and dec--that may not be available on all processors) 此外, Interlocked在不支持这些CAS指令的处理器上提供原子使用(以及其他可能非原子指令,如inc和dec - 可能并非在所有处理器上都可用)

If 'b' is not volatile, will this operation treat it as such? 如果'b'不是易变的,这个操作会不会这样处理?

I don't think you should ever use this when b is a shared variable. b是共享变量时,我认为你不应该使用它。 So that eliminates the whole problem. 这样就消除了整个问题。 But Exchange will always use a Memorybarrier so the answer is probably Yes. 但Exchange总会使用Memorybarrier,所以答案可能是肯定的。

when is interlocked.exhange useful if we don't care about the previous value of 'a'? 何时是interlocked.exhange有用,如果我们不关心'a'的先前值?

The overload for double is very useful because writes to double are otherwise not atomic. double的重载非常有用,因为写入double不是原子的。 Same for Int64 on 32 bits systems. 32位系统上的Int64也是如此。

But for the Exchange() overloads on atomic types the use case is less clear. 但是对于原子类型的Exchange()重载,用例不太清楚。 I think most algorithms would favor CompareExcange() . 我认为大多数算法都支持CompareExcange()

So consider it the atomic Write(). 所以考虑一下原子Write()。

If 'b' is not volatile, will this operation treat it as such? 如果'b'不是易变的,这个操作会不会这样处理?

Yes, because according to this source , all methods of the Interlocked class generate implicit memory fences. 是的,因为根据这个来源Interlocked类的所有方法都会生成隐式内存栅栏。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM