【问题标题】:Can a thread-local copy of select elements be created of a shared 2D array in a parallel region? (Shared, private, barrier: OPenMP)可以在并行区域中创建共享二维数组的选择元素的线程本地副本吗? (共享、私有、屏障:OPenMP)
【发布时间】:2018-01-27 11:03:56
【问题描述】:

我有一个由nxn 元素组成的二维网格。在一次迭代中,我通过平均其邻居的值来计算一个元素的值。那就是:

    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            grid[i][j] = (grid[i-1][j] + grid[i][j-1] + grid[i+1][j] + grid[i][j+1])/4.0;

我需要为iter 的迭代次数运行上述嵌套循环。 我需要的是以下内容:

  1. 我需要线程来计算这个平均值,等到所有线程都完成计算,然后一次性更新网格。
  2. 具有iter 迭代的循环将按顺序运行,但每次迭代期间,每个ijgrid[i][j] 值应并行计算。

为此,我有以下想法和问题:

  1. 也许使网格 共享 并通过仅将这 4 个元素 私有 复制到线。 (基本上网格由所有线程共享,但每个线程中也有 4 个 iteration-specific 元素的本地副本。)这可能吗?强>
  2. 实际上是否需要 barrier 才能让所有线程完成并开始下一次迭代?

我对 OpenMP 的思维方式非常陌生,我完全迷失在这个简单的问题中。如果有人能帮助解决我的困惑,我将不胜感激。

【问题讨论】:

  • 当前您正在根据同一数组的邻居计算平均值,并立即将其写入当前数组元素。顺便说一句,这看起来很可疑,因为 depedenices。一旦你去并行线程,你将不得不做一个非常复杂的同步方案,让正确的线程等待其他线程的结果。即网格 [2][2] 的计算更新必须等到 [1][1]、[3,2] 和所有其他邻居的计算完成。和其他应该等待 gheir 邻居,...否则你将有未定义的行为。这是你想要的吗?
  • 您应该能够找到有关 jacobi 迭代并行性的有用讨论。它可能会超出临界范围。
  • 一种简单的方法是将所有工作保存到第二个网格中。当你的计算全部完成后,你可以交换网格和网格2。
  • 低效怎么办?记忆?您需要 2 个副本,无论如何您都需要。它可以是 OpenMP 友好的,如果处理得当(交换指针),后循环更新会非常快。
  • @complextea 在您的示例中它不能像这样工作。您使用以前在其他迭代中计算的平均值。您需要第二个数组来保存结果。在这种情况下,您可以在每次迭代中使用线程,而无需同步(“join”除外)。这很可能是矫枉过正。您只需要定义其中的几个,即 8 并重用。

标签: c++ multithreading openmp barrier


【解决方案1】:
  1. 在实践中,您希望线程数比网格点少(多),因此每个线程将计算一大堆点(例如,一行)。启动 OpenMP(或任何其他类型的)线程会产生一定的开销,而且您的程序将受内存限制,而不是受 CPU 限制。因此,每个网格点启动一个线程将破坏并行计算的整个目的。因此,不推荐您的想法 #1(虽然我不太确定我是否理解正确;也许这不是您的提议)。

  2. 我会建议(OP cmets 中的其他人也指出)您分配存储网格值所需的两倍内存并使用在迭代之间交换的两个指针:一个指向保存先前迭代值的内存只读,另一个是只写的新迭代值。请注意,您只会交换指针,而不是实际复制内存。迭代完成后,您可以将最终结果复制到所需位置。

  3. 是的,您需要在迭代之间同步线程,但是在 OpenMP 中,这通常是通过在迭代循环中打开一个并行区域来隐式完成的(在并行区域的末尾有一个隐式屏障):

    for (int iter = 0; iter < niter; ++iter)
    {
        #pragma omp parallel
        {
            // get range of points for current thread
            // loop over thread's points and apply the stencil
        }
    }
    

    或者,使用parallel for 构造:

    const int np = n*n;
    for (int iter = 0; iter < niter; ++iter)
    {
        #pragma omp parallel for
        for (int ip = 0; ip < np; ++ip)
        {
            const int i = ip / n;
            const int j = ip % n;
            // apply the stencil to [i,j]
        }
    }
    

    第二个版本将在可用线程之间自动平均分配工作,这很可能是您想要的。首先,您必须手动完成。

【讨论】:

  • 我只是想对您的回答再提出一个疑问。你的意思是说第二个版本会自动分发,因为第二个版本中存在 for 指令而第一个版本中不存在?
  • @complextea 差不多,是的。当编译器看到parallel for 构造时,它会为每个线程适当地设置循环条件。有不同的调度模式,但默认的通常意味着“平均分配工作”。一个简单的parallel 区域仅表示“在每个线程中执行此代码”,然后由程序员来确定要完成的工作,例如使用 OpenMP 线程数。当工作负载分配比单个“for”循环更复杂时,这有时是可取的。
猜你喜欢
  • 1970-01-01
  • 2016-06-21
  • 2016-07-13
  • 1970-01-01
  • 2016-05-17
  • 1970-01-01
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
相关资源
最近更新 更多