是否有系统的方法来知道 C# 中的操作是否是原子的? 或者有什么一般准则或经验法则吗?
欲了解更完整/详细的内容:
读取和写入 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
}
是的。 阅读 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 整除。
从.Net8开始,我们有这个文档:https://github.com/dotnet/runtime/blob/main/docs/design/specs/Memory-model.md#alignment
我们对对齐和原子内存访问部分感兴趣。
阅读链接了解详细信息,但总的来说:
内存访问正确对齐的原始类型和枚举类型的数据 直到平台指针大小的大小始终是原子的。