1

这是我的情况,我有一个指向一些数据数组的指针数组......让我们说:

    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。但是当我使用相同的数据块数组 [0] 时,每个函数调用持续 4 段。

我的理论是,没有办法知道数组 [0] 是否会被函数更改,所以每个线程都要求一个副本并使其他线程拥有的副本无效,这应该解释延迟......

我试图像这样制作 array[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()];
    }

但我得到了相同的结果......就像线程没有“释放”数据块,所以其他线程可以使用它......

我必须注意,第一个参数并不总是 array[0] 所以我不能在 pragma 行中使用 firstprivate(array[0]) ...

问题是:

  • 难道我做错了什么?
  • 有没有办法“释放”一个共享的内存块,以便其他线程可以使用它?

试图让我理解非常困难,所以如果您需要更多信息,请告诉我!

在此先感谢...哈维尔

编辑:我无法更改函数声明,因为它位于库中!(ACML)

4

2 回答 2

2

我认为您的分析是正确的,编译器无法知道指向的数组在他背后没有改变。实际上他知道它们可能会改变,因为线程也0接收相同array[0]的可修改参数。

所以他必须经常重新加载这些值。首先,您应该声明您的函数,例如

void function(Data const*restrict A, Data*restrict B);

这首先告诉编译器,其中的值A不能更改,然后没有一个指针可以被另一个(或任何其他指针)别名,因此他知道数组中的值将仅由函数本身更改。

对于线程号0,上面的断言不正确,数组A实际上B是相同的。因此,您最好在进入之前array[0]复制到一个 common ,并将其作为第一个参数传递给每个线程:temparray #pragma omp paralleltemparray

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()];
于 2013-03-23T22:56:39.250 回答
0

我认为你的分析是错误的。如果数据没有改变,恕我直言,它不会在核心之间同步。放缓有两个可能的原因。

  1. 核心 #0 得到function(array[0], array[0]). 你说第一个参数是只读的,但第二个不是。所以核心#0会改变数据,array[0]CPU必须一直在核心之间同步这些数据。

  2. 第二个可能的原因是您的数组很小(20 个元素)。发生的情况是核心 #1 获得指向 20 元素数组的指针,核心 #2 获得指向数组的指针,这可能就在内存中的数组 #1 之后。因此,它们很有可能位于同一高速缓存行上。CPU 不会跟踪每个特定元素的变化——如果它发现同一缓存行上的元素发生了变化,它将在内核之间同步缓存。解决方案是使每个数组更大(这样在 20 个元素之后,您的未使用空间等于缓存大小(128K?256K?))

我猜你的代码中同时存在#1 和#2 问题。

于 2017-07-07T09:39:30.433 回答