有没有办法在 C# 中以与 C++ 中相同的方式对齐对象以避免错误共享?

Is there a way to align objects in C# same way as in C++ to avoid false sharing?

我是 C++ 开发者,正在从事 C# 项目。
我遇到过以下情况。

我有 class MyClass 并希望避免任何 2 个 MyClass 类型的对象共享缓存行,即使我有一个数组或任何 MyClass 类型的顺序集合也是如此。
在 C++ 中,我们可以声明 class alignas(hardware_destructive_interference_size) Myclass,这将确保任何 2 个对象永远不会共享缓存行。

C#中是否有等效的方法?

不,您无法控制 classes(引用类型)的对齐方式或内存位置。您甚至无法获得内存中 class 实例的大小。

可以控制结构(以及其中的字段)的大小和对齐方式。结构是值类型,其工作方式与 C++ 中的几乎相同。如果你创建一个结构数组,每个条目都有结构的大小,如果足够大,你可以得到你想要的。但是不能保证各个条目确实分布在缓存行中。这也取决于缓存的大小和组织。

另请注意,托管实例(无论是 class 还是结构)的地址可以在运行时更改。允许垃圾收集器四处移动实例以压缩堆,并且它会经常这样做。所以也不能保证同一个实例总是在同一个缓存行中结束。可以在某个块执行时“固定”一个实例,但这主要是在与本机函数接口时而不是在性能优化的上下文中。

aligned_alloc 将大小四舍五入到最近的缓存行。

根据阅读 this page,在我看来你可以使用以下内容 - 仅用于 structs,而不是 classes(我的示例将用于 Intel CPU) :

[StructLayout(LayoutKind.Sequential, Pack=64)]

我无法在任何地方看到以这种方式定义的对象实际上会 分配 在(或实际上保留在)64 字节边界上的保证,但这种构造会如果不是,就没有多大用处。如果您想检查(我个人肯定会),这里有一些关于如何获取已分配对象的地址(直到它移动!)的建议:

Memory address of an object in C#

我也看不出有什么办法不 hard-coding 缓存行大小,但是如果你总是 运行 你的代码在 Intel CPU 上那么不应该一个问题,我认为(大多数)ARM 芯片也使用 64 字节,虽然不是,apparently,Apple 的 M1(呵呵!,典型)。

当然,如果你这样做你需要相应地对齐相应的C++ class / struct。我认为 hard-code 也将对齐设置为 64 字节是明智的,不是吗? :)