这是我的情况,我有一个指针数组,指向一些数据的数组...让我们说:
Data** array = malloc ( 100 * sizeof(Data*));
for(i = 0; i < 100; i++) array[i] = malloc (20 * sizeof(Data);
在并行区域内,我进行了一些使用该数据的操作。例如:
#pragma omp parallel num_threads(4) firstprivate(array)
{
function(array[0], array[omp_get_thread_num()];
}
第一个参数是只读的,但在所有线程中都是相同的......
问题在于,如果我使用不同的数据块作为第一个参数,即:array [omp_get_thread_num()+ 1],则每个函数持续1seg。但是当我使用相同的数据块时,array [0],每个函数调用会持续4segs。
我的理论是,没有办法知道函数是否会被函数更改,因此每个线程都要求复制并使其他线程拥有的副本无效,这应该解释延迟。
我试着像这样制作一个数组[0]的本地副本:
#pragma omp parallel num_threads(4) firstprivate(array)
{
Data* tempData = malloc(20 * sizeof(Data));
memcpy(tempData,array[0], 20*sizeof(Data));
function(tempData, array[omp_get_thread_num()];
}
但是我得到了相同的结果......这就像线程没有'释放'数据块所以其他线程可以使用它......
我必须注意第一个参数并不总是数组[0]所以我不能在pragma行中使用firstprivate(array [0])...
问题是:
尝试让我理解是非常困难的,如果您需要更多信息,请告诉我!
提前致谢... Javier
编辑:我无法更改函数声明,因为它来自一个库! (ACML)
答案 0 :(得分:2)
我认为你的分析是正确的,编译器无法知道指向的数组在他背后没有改变。实际上他知道他们可能会改变,因为线程0
也接收相同的array[0]
作为可修改的参数。
所以他必须经常重新加载这些值。首先,您应该声明您的函数类似
void function(Data const*restrict A, Data*restrict B);
这首先告诉编译器,A
中的值不能改变,然后没有一个指针可以被另一个(或任何其他指针)别名,所以他我知道数组中的值只会被函数本身改变。
对于线程号0
,上面的断言不正确,数组A
和B
实际上是相同的。因此,在进入array[0]
之前,最好将temparray
复制到公共#pragma omp parallel
,并将相同的temparray
作为第一个参数传递每个线程:
Data const* tempData = memcpy(malloc(20 * sizeof(Data)), array[0], 20*sizeof(Data));
#pragma omp parallel num_threads(4)
function(tempData, array[omp_get_thread_num()];
答案 1 :(得分:0)
我认为你的分析错了。如果数据未更改,则不会在核心之间同步。减速有两个可能的原因。
核心#0获得function(array[0], array[0])
。你说第一个参数是只读的,但第二个参数不是。所以核心#0将改变array[0]
中的数据,并且CPU必须始终在核心之间同步这些数据。
第二个可能的原因是阵列的小尺寸(20个元素)。会发生的是核心#1获取指向20个元素数组的指针,核心#2获取指向数组的指针,这可能就在内存中的数组#1之后。因此,它们很可能位于同一缓存线上。 CPU不跟踪更改每个特定元素 - 如果它看到同一缓存行上的元素发生更改,它将同步核心之间的缓存。解决方案是使每个数组变大(这样在20个元素之后你有未使用的空间等于缓存大小(128K?256K?))
我猜您的代码中存在#1和#2两个问题。