Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.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
多线程和CPU缓存_C_Multithreading_Caching - Fatal编程技术网

多线程和CPU缓存

多线程和CPU缓存,c,multithreading,caching,C,Multithreading,Caching,我正在使用多线程在C中实现一个图像过滤操作,并使其尽可能优化。但是我有一个问题:如果一个内存被线程0访问,并且如果同一个内存被线程1同时访问,它会从缓存中获取它吗?这个问题源于这两个线程可能运行在CPU的两个不同内核中。因此,另一种说法是:所有的核心是否共享相同的公共缓存 假设我有一个如下所示的内存布局 int输出[100] 假设有2个CPU内核,因此我生成了两个线程来并发工作。一种方案是将内存分成两个块,0-49和50-99,让每个线程处理每个块。另一种方法是让thread-0处理偶数索引,如

我正在使用多线程在C中实现一个图像过滤操作,并使其尽可能优化。但是我有一个问题:如果一个内存被线程0访问,并且如果同一个内存被线程1同时访问,它会从缓存中获取它吗?这个问题源于这两个线程可能运行在CPU的两个不同内核中。因此,另一种说法是:所有的核心是否共享相同的公共缓存

假设我有一个如下所示的内存布局

int输出[100]


假设有2个CPU内核,因此我生成了两个线程来并发工作。一种方案是将内存分成两个块,0-49和50-99,让每个线程处理每个块。另一种方法是让thread-0处理偶数索引,如024等等。。而另一个线程处理奇数索引,如1 3 5。。。。后一种技术更容易实现(特别是对于3D数据),但我不确定是否可以通过这种方式有效地使用缓存。

我可能弄错了,但核心缓存是否共享取决于CPU的实现。您必须查看制造商页面上的技术表,以检查CPU中的每个核心是否有自己的缓存,或者缓存是否共享

我在一家安全公司从事图像处理工作,有时在线程上运行批处理操作后,我们会得到损坏的图像。经过长时间的调查,我们得出结论,缓存是在CPU核心之间共享的,在极少数情况下,数据被覆盖或替换为不正确的数据


这是一个需要考虑的问题,还是一个非常罕见的事件,我无法回答。

这个问题的答案很大程度上取决于体系结构和缓存级别,以及线程实际运行的位置

例如,最近的Intel多核CPU具有每个内核的一级缓存,以及在同一CPU包中的内核之间共享的二级缓存;但是,不同的CPU包将有自己的二级缓存

即使在一个包中的两个内核上运行线程的情况下,如果两个线程都访问同一缓存线中的数据,那么该缓存线将在两个L1缓存之间跳转。这是非常低效的,您应该设计算法来避免这种情况


一些评论询问了如何避免这个问题

从本质上讲,这并不是特别复杂——您只想避免两个线程同时尝试访问位于同一缓存线上的数据,其中至少有一个线程正在写入数据。(只要所有线程都只读取数据,就没有问题——在大多数体系结构上,只读数据可以存在于多个缓存中)

要做到这一点,您需要知道缓存线的大小-这因体系结构而异,但目前大多数x86和x86-64系列芯片使用64字节缓存线(有关其他体系结构,请参阅您的体系结构手册)。您还需要知道数据结构的大小

如果您要求编译器将感兴趣的共享数据结构与64字节边界对齐(例如,您的数组
输出
),则您知道它将从缓存线的开始处开始,并且您还可以计算后续缓存线边界的位置。如果
int
是4个字节,那么每个缓存行将正好包含8个
int
值。只要数组在缓存线边界上启动,那么
output[0]
output[7]
将在一条缓存线上,而
output[8]
output[15]
将在下一条缓存线上。在本例中,您将设计算法,使每个线程在一个相邻
int
值块上工作,该值是8的倍数

如果存储的是复杂的
struct
类型,而不是普通的
int
,则该实用程序将非常有用。它将分析编译的二进制文件中的
struct
类型,并显示布局(包括填充)和总大小。然后,您可以使用此输出调整
struct
s,例如,您可能希望手动添加一些填充,以便
struct
是缓存线大小的倍数


在POSIX系统上,
POSIX_memalign()
函数用于分配具有指定对齐方式的内存块。

一般来说,共享重叠内存区域是个坏主意,就像一个线程处理0,2,4。。。其他过程1,3,5。。。尽管有些体系结构可能支持这一点,但大多数体系结构都不支持,而且您可能无法指定代码将在哪些机器上运行。此外,操作系统还可以自由地将代码分配给它喜欢的任何核心(单个核、同一物理处理器上的两个核,或单独处理器上的两个核)。此外,每个CPU通常都有一个单独的一级缓存,即使它位于同一个处理器上

在大多数情况下,0,2,4…/1,3,5。。。将极大地降低性能,甚至可能比单个CPU慢。 赫伯·萨特尔斯很好地证明了这一点


在大多数系统上,使用方案[…n/2-1]和[n/2…n]可以更好地扩展。它甚至可能导致超线性性能,因为可以使用所有CPU的缓存大小之和。使用的线程数应始终是可配置的,并应默认为找到的处理器内核数

英特尔文档

英特尔发布的文件可能包含此类信息

例如,对于我在旧计算机上使用的处理器i5-3210M,我查找3.3“英特尔超线程技术(英特尔HT技术)”时说:

处理器支持英特尔超线程技术(英特尔HT技术) 这允许执行核心作为两个逻辑处理器运行。虽然