use*_*225 3 c# multithreading .net-4.0 interlocked
我有一些简单(希望)的问题,我一直无法找到答案 -
假设我有多个线程可以访问的对象a,b.
Interlocked.Exchange(ref a, b)
Run Code Online (Sandbox Code Playgroud)
如果'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'的先前价值?
传递给的变量Exchange(或传递给任何方法的任何volatile变量)在传递时都不会保留"volatile"......实际上不需要它volatile(在方法调用期间),因为唯一volatile能做的就是确保编译器不优化变量的使用(这通常意味着优化写入寄存器,因此值只能由单个处理器"看到").在x86/x64以外的处理器上,这有时意味着保证获取或释放语义的指令..NET不使用寄存器进行参数传递,因此volatile不会影响传递的参数的"波动性".由于内存模型的可见性保证,它必须始终从内存中获取最新值
RE问题2:引用是"真实的",取决于字段的声明,有可见性保证wrt字段; 但是没有"volatile"字段访问可以在某些使用阶段被优化到寄存器中,可能隐藏来自其他处理器的某些写入.
Interlocked交换使非原子操作看起来是原子的.交换本质上类似于:
var x = someVariable;
someVariable = y;
Run Code Online (Sandbox Code Playgroud)
无论类型如何,这都不可能是原子的someVariable. Exchange使这个操作成为原子.这也是原子与非原子类型,如double,long(在32位)等.
的哪一部分Exchange确实使这个原子是使用内存围栏-这使得写入可见,而不是重新排序,指令存储器栅栏后的顺序相同的内存地址的读取.
Exchange如果你不关心'a'的先前值,你为什么要使用?如果你不关心实际的"交换",那么VolatileWrite似乎更合适.
或者,如果不需要"交换",您可以编写线程安全代码来模拟"A = B",如下所示:
Thread.MemoryBarrier();
A=B;
Run Code Online (Sandbox Code Playgroud)
FWIW Interlocked部分地模拟了某些处理器中的比较和交换(CAS)指令.这些指令允许您在一条指令中执行这两项操作(使其成为原子).如果没有这样的东西Interlocked,编译器可能很难推断出应该使用这些CAS指令之一.此外,Interlocked在不支持这些CAS指令的处理器上提供原子使用(以及其他可能非原子指令,如inc和dec - 可能并非在所有处理器上都可用)
| 归档时间: |
|
| 查看次数: |
3166 次 |
| 最近记录: |