如果我编写一段代码,其中每个线程修改数组的完全不同部分,那会保持缓存一致性吗?

Posted

技术标签:

【中文标题】如果我编写一段代码,其中每个线程修改数组的完全不同部分,那会保持缓存一致性吗?【英文标题】:If I make a piece of code in which each thread modifies completely different parts of an array, will that maintain cache coherency? 【发布时间】:2016-12-09 20:17:31 【问题描述】:

所以我正在使用 OpenMP 编写一些并行代码(但这个问题应该合理地适用于其他框架),其中我有一个对象数组:

std::vector<Body> bodies;

然后我做了一个小的并行循环来对bodies 做一些事情。在这个并行部分的开始,设置了一组线程来单独执行循环。该循环基本上使用每个Body 上的foo 的值(除了有问题的那个)来更新有问题的主体上的bar 的值。所以基本上没有对每个主体上的foo 的值进行写入,并且对bar 进行的唯一读取被本地化到控制该特定主体的线程;在伪代码中,它看起来像这样:

//create team of threads, and then this section is executed by each thread separately
for each Body i
    for each Body j =/= i
        i.bar += (j.foo * 2);
    end for
end for

我的问题是,这是否会像我认为的那样保持缓存的一致性?因为在我看来,没有一个线程会触及其他线程正在编辑的东西,所以我觉得它应该是安全的。但这是我需要写的报告中非常重要的一点,所以我想确定一下。

谢谢。

【问题讨论】:

仅从伪代码中很难验证您是否了解如何正确使用 OpenMP。您能否使用实际的#pragma omp 将其更新为实际的 C++?最好还具有Body 的定义。我知道你已经有了答案,但我觉得可以更具体地回答你的问题。 【参考方案1】:

如果您有多个线程并且其中至少一个是写入器并且线程正在访问同一个对象,则规则是您需要同步。如果您的所有线程都在读取,那么您根本不需要任何同步。

如果您正在写入数组/向量,但每个线程都在写入自己的唯一部分,那么您不需要任何同步,因为您没有访问相同的底层对象(只要您没有修改向量本身,例如添加或删除元素)。唯一的危险是false sharing。如果两个线程在阵列的不同部分工作,但它们碰巧在同一个缓存行上,那么任何修改都会弄脏缓存行,两个线程都会受到影响。但这只是对性能的影响,不会导致未定义的行为。

【讨论】:

非常感谢您的及时答复!我会记住不要弄乱数组/向量本身,我会留意虚假共享性能的影响,看看它是否对我的程序有显着影响。 我对在此答案中使用术语 variable 有疑问。 内存区域存储位置。此外,您还没有考虑写入顺序及其可见性很重要的场景。

以上是关于如果我编写一段代码,其中每个线程修改数组的完全不同部分,那会保持缓存一致性吗?的主要内容,如果未能解决你的问题,请参考以下文章

遍历数组和线程时访问冲突

MIPS 快速排序数组

什么词是指可以由两个不同的线程同时/并行执行的代码段/功能?

java多线程访问同一个数组,存在并发问题吗,每个线程访问的是数组的不同部分,不存在冲突

SQL - 使用数组

操作不同的数组(对象数组)索引时是不是需要同步