C# 中哪些操作是原子操作?

问题描述 投票:0回答:4

是否有系统的方法来知道 C# 中的操作是否是原子的? 或者有什么一般准则或经验法则吗?

c# .net multithreading atomic
4个回答
49
投票

欲了解更完整/详细的内容:

读取和写入 32 位值类型是原子的:这包括以下内在值(结构)类型:

bool, char, byte, sbyte, short, ushort, int, uint, float
。 以下类型(除其他外)不保证是原子的:
decimal, double, long, ulong

例如

int x;
x = 10; // atomic
decimal d;

d = 10m; // not atomic

引用赋值也是一个原子操作:

private String _text;
public void Method(String text)
{
  _text = text; // atomic
}

35
投票

是的。 阅读 CLI 规范:http://www.ecma-international.org/publications/standards/Ecma-335.htm。 例如:

I.12.6.6 原子读写

符合要求的 CLI 应保证对 正确对齐的内存位置不大于本机字大小 (native int 类型的大小)是原子的(参见§I.12.6.2) 对某个位置的写访问大小相同。 原子写入应 除写入的位外,不更改其他位。 除非明确布局 控制(参见分区 II(控制实例布局))用于 改变默认行为,数据元素不大于自然值 字大小(本机 int 的大小)应正确对齐。 对象引用应被视为存储在 原生字号。

[注意:不保证原子更新 内存的(读取-修改-写入),为此提供的方法除外 目的作为类库的一部分(参见分区 IV)。 一个原子 写入“小数据项”(不大于本地单词的项) size)需要在硬件上进行原子读/修改/写 不支持直接写入小数据项。尾注]

[注: 当 a 的大小超过 8 字节时,无法保证对 8 字节数据进行原子访问。 本机 int 是 32 位,尽管某些实现可能会执行 当数据在 8 字节边界上对齐时的原子操作。结尾 注]

关于64位长的问题,Eric Lippert在这里回答:https://ericlippert.com/2011/05/31/atomicity-volatility-and-immutability-are- Different-part-two/

CLI规范实际上做出了更有力的保证。命令行界面 保证读取和写入值类型的变量 处理器自然指针大小的大小(或更小)是 原子;如果您在 64 位操作系统上运行 C# 代码 64 位版本的 CLR 然后读取和写入 64 位双精度数和 长整数也保证是原子的。 C# 语言可以 不能保证这一点,但运行时规范可以保证。 (如果您运行的是 C# 某些环境中的代码未被某些人实现 CLI 的实现那么你当然不能依赖它 保证;如果您愿意,请联系向您出售运行时的供应商 了解他们提供什么保证。)

关于原子访问的另一个微妙之处是底层 处理器仅在读取变量或 写入与右对齐的存储相关联 内存中的位置。最终该变量将被实现为 指向内存某处的指针。在 32 位操作系统上, 指针必须能被 4 整除才能进行读取或写入 保证是原子的,并且在 64 位操作系统上它具有 能被 8 整除。


8
投票

您可以在此处获取 CLI 规范:

“符合要求的 CLI 应保证对 正确对齐的内存位置不大于本机字大小 (native int 类型的大小)是原子的……”

C# 规范第 12.5 节此处

“以下数据类型的读写应是原子的:bool、 char、byte、sbyte、short、ushort、uint、int、float 和引用 类型。”另外:“……不能保证原子读-修改-写, 例如递增或递减的情况。”

使用 this 使增量操作原子化。


0
投票

从.Net8开始,我们有这个文档:https://github.com/dotnet/runtime/blob/main/docs/design/specs/Memory-model.md#alignment
我们对对齐原子内存访问部分感兴趣。
阅读链接了解详细信息,但总的来说:

内存访问正确对齐的原始类型和枚举类型的数据 直到平台指针大小的大小始终是原子的。

© www.soinside.com 2019 - 2024. All rights reserved.