Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/272.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#如何保证读/写操作的原子性?_C#_Atomic - Fatal编程技术网

C#如何保证读/写操作的原子性?

C#如何保证读/写操作的原子性?,c#,atomic,C#,Atomic,C规范在第5.5节中规定,对某些类型(即bool、char、byte、sbyte、short、ushort、uint、int、float)和参考类型)的读写保证为原子类型 这引起了我的兴趣。你怎么能做到?我的意思是,我卑微的个人经历只告诉我,如果我想让读写看起来原子化,就要锁定变量或使用障碍;如果必须对每一个读/写操作都执行此操作,那么这将是一个性能杀手。然而C#做了一些类似的事情 也许其他语言(如Java)也能做到这一点。我真的不知道。我的问题并不是专门针对语言的,只是我知道C#可以做到 我知

C规范在第5.5节中规定,对某些类型(即
bool
char
byte
sbyte
short
ushort
uint
int
float
)和参考类型)的读写保证为原子类型

这引起了我的兴趣。你怎么能做到?我的意思是,我卑微的个人经历只告诉我,如果我想让读写看起来原子化,就要锁定变量或使用障碍;如果必须对每一个读/写操作都执行此操作,那么这将是一个性能杀手。然而C#做了一些类似的事情

也许其他语言(如Java)也能做到这一点。我真的不知道。我的问题并不是专门针对语言的,只是我知道C#可以做到

我知道它可能需要处理某些特定的处理器指令,在C/C++中可能不可用。然而,我仍然想知道它是如何工作的


[编辑]说实话,我相信在某些情况下,读和写可能是非原子的,就像一个CPU可以访问一个内存位置,而另一个CPU正在那里写。只有当CPU不能同时处理所有对象时才会发生这种情况,比如因为对象太大或者内存没有在正确的边界上对齐?

您不能。即使一直到汇编语言,您也必须使用特殊的锁操作码,以确保不会出现另一个核心或进程,并消除您所有的辛苦工作。

对x86的读写无论如何都是原子的。它在硬件级别得到支持。然而,这并不意味着像加法和乘法这样的运算是原子的;它们需要加载、计算,然后存储,这意味着它们可以进行干扰。这就是锁前缀的作用


你提到了锁定和记忆障碍;它们与读写的原子性无关。在x86上,无论是否使用内存屏障,都无法看到半写的32位值。

这些类型保证原子性的原因是它们都是32位或更小的。由于.NET仅在32位和64位操作系统上运行,因此处理器体系结构可以在单个操作中读取和写入整个值。这与32位平台上的Int64不同,它必须使用两个32位操作进行读写


我不是一个真正的硬件爱好者,所以如果我的术语让我听起来像个小丑,我很抱歉,但这是我的基本想法。

在x86和x64内核上实现原子性保证是相当便宜的,因为CLR只承诺32位或更小的变量具有原子性。所需要的只是变量正确对齐并且不跨缓存线。JIT编译器通过在4字节对齐的堆栈偏移量上分配局部变量来确保这一点。GC堆管理器对堆分配执行相同的操作

值得注意的是,CLR保证不是一个很好的保证。对齐承诺不够好,无法编写对double数组具有一致性能的代码。很好的演示了。由于这个原因,与使用SIMD指令的机器代码进行互操作也非常困难。

是的,C#和Java保证某些基本类型的加载和存储是原子的,就像您所说的那样。这很便宜,因为能够运行.NET或JVM的处理器确实保证了适当对齐的原语类型的加载和存储是原子的


现在,C#和Java以及它们运行的处理器都不能保证而且代价高昂的是,它们发出了内存障碍,以便这些变量可以用于多线程程序中的同步。但是,在Java和C中,您可以使用“volatile”属性标记变量,在这种情况下,编译器会负责发出适当的内存屏障。

那么.net抖动就是在幕后这么做的?为每一个读写非局部变量添加锁?我不会声称知道所有细节。我是从一般的角度讲的。我不知何故认为,在另一个CPU的写操作期间,另一个线程有可能访问内存位置,从而导致不一致的结果。我一直都错了吗?除了原子读/写之外,还有很多其他问题。在相同变量上运行的两个线程很可能会导致不希望的结果,因为它们经常读取/修改/写入非原子变量。在需要特殊处理的多处理器机器上也存在内存可见性问题care@nos:我明白。不过,这不是我现在关心的问题。:)它实际上只是关于读和写。是的,我知道乘法和它们的朋友不是原子的。在我这方面从来没有混乱过。我不知何故相信,一个CPU可以在另一个CPU写入内存时访问内存,这可能导致读取结果不一致。它会发生吗?如果是的话,我能做点什么使它不会发生吗?我觉得奇怪的是,内存分配器试图通过将double数组强制到LOH来解决double数组的对齐问题,而不是说每当GC分配或复制一个包含32项或更大项的
double[]
时,下一个可用空间不是64位对齐的,它应该首先分配并丢弃一个12字节的虚拟对象。5%的内存浪费应该比强制执行LOH的开销少。