我正在使用多个线程在 C 中实现图像过滤操作,并使其尽可能优化。但我有一个问题:如果线程 0 访问内存,并且同时线程 1 访问同一内存,它会从缓存中获取它吗?这个问题源于这两个线程可能运行在 CPU 的两个不同内核中的可能性。因此,另一种说法是:所有内核是否共享相同的公共高速缓存?
假设我有如下的内存布局
整数输出[100];
假设有 2 个 CPU 核心,因此我生成两个线程来并发工作。一种方案是将内存分为两个块:0-49 和 50-99,并让每个线程在每个块上工作。另一种方法可能是让线程 0 处理偶数索引,如 0 2 4 等。而另一个线程处理奇数索引,如 1 3 5 ...。后面的技术更容易实现(特别是对于 3D数据),但我不确定是否可以通过这种方式有效地使用缓存。
这个问题的答案很大程度上取决于体系结构和缓存级别,以及线程实际运行的位置。
例如,最近的 Intel 多核 CPU 具有每个核心的 L1 高速缓存,以及在同一 CPU 封装中的核心之间共享的 L2 高速缓存;然而,不同的 CPU 封装将有自己的 L2 缓存。
即使当您的线程在一个包内的两个核心上运行时,如果两个线程都访问同一缓存行中的数据,则该缓存行将在两个 L1 缓存之间跳跃。这is效率非常低,你应该设计你的算法来避免这种情况。
有一些评论询问如何避免这个问题。
从本质上讲,它实际上并不是特别复杂 - 您只是想避免两个线程同时尝试访问位于同一缓存行上的数据,其中至少有一个线程正在写入数据。 (只要所有线程都只reading数据,没有问题 - 在大多数架构上,只读数据可以存在于多个缓存中)。
为此,您需要知道缓存行大小 - 这因体系结构而异,但目前大多数 x86 和 x86-64 系列芯片使用 64 字节缓存行(有关其他体系结构,请参阅体系结构手册)。您还需要知道数据结构的大小。
如果您要求编译器将感兴趣的共享数据结构与 64 字节边界对齐(例如,您的数组output
),那么您就知道它将从一个缓存行的开头开始,并且您还可以计算后续缓存行边界在哪里。如果你的int
是 4 个字节,那么每个缓存行将包含 8 个字节int
价值观。只要数组从缓存行边界开始,那么output[0]
通过output[7]
将位于一个缓存行上,并且output[8]
通过output[15]
就下一个。在这种情况下,您将设计算法,使每个线程在相邻的块上工作int
值是 8 的倍数。
如果您存储复杂struct
类型而不是简单的int
, the pahole http://lwn.net/Articles/206805/实用性将会有用。它将分析struct
在编译的二进制文件中输入类型,并向您显示布局(包括填充)和总大小。然后你可以调整你的struct
使用此输出 - 例如,您可能需要手动添加一些填充,以便您的struct
是高速缓存行大小的倍数。
在 POSIX 系统上,posix_memalign()
函数对于分配具有指定对齐方式的内存块非常有用。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)