今天在并行编程课上,我和教授对什么是“虚假共享”有了不同的理解。我的教授说的毫无意义,所以我立即指出。她认为“虚假分享”会导致程序结果出现错误。
我说过,当不同的内存地址分配给同一个缓存行时,就会发生“错误共享”,向其中一个地址写入数据会导致另一个地址被踢出缓存。如果处理器在两个虚假共享地址之间不断写入,则两者都无法保留在缓存中,因此所有操作都将导致对 DRAM 的访问。
这是我到目前为止的看法。事实上,我也不确定我说了什么......如果我有误解,请指出。
所以有一些问题。缓存假定为 64 字节对齐、4 路组关联。
我将针对您的问题分享我的观点。
分隔的字节数多于块大小的两个地址不会驻留在完全相同的缓存行上。因此,如果一个核心在其缓存中具有第一个地址,而另一个核心请求第二个地址,则第一个核心不会因为该请求而从缓存中删除。这样就不会出现错误的分享失败情况。
我无法想象在完全没有并发的情况下会如何发生错误共享,因为除了单个线程之外不会有其他人来竞争缓存行。
取自here,使用 OpenMP,重现错误共享的一个简单示例是:
double sum=0.0, sum_local[NUM_THREADS];
#pragma omp parallel num_threads(NUM_THREADS)
{
int me = omp_get_thread_num();
sum_local[me] = 0.0;
#pragma omp for
for (i = 0; i < N; i++)
sum_local[me] += x[i] * y[i];
#pragma omp atomic
sum += sum_local[me];
}
一些一般指出,我可以想到避免错误共享的方法是:
a.尽可能使用私人数据。
b.有时,您可以使用 padding 来对齐数据,以确保没有其他变量会驻留在共享数据所在的同一缓存中。
欢迎指正或补充。
某些语言(或方言)可以提供解决问题的方案
例如,最近的 C23 和 C++ 有一个特殊的
alignas
说明符,可以帮助自动将数据分开,因此无需手动填充。
https://stackoverflow.com/a/62491456/5874981说明了alignas说明符对于可由多个执行线程共享的事件的用法。
在 Sun 的 Java 8 中,您可以将数据注释为“已竞争”