1

我正在编写更多具有以下示意图的计算代码:

#pragma omp parallel
{
    #pragma omp for nowait
    // Compute elements of some array A[i] in parallel

    #pragma omp single
    for (i = 0; i < N; ++i) {
        // Do some operation with A[i].
        // This time it is important that operations are sequential. e.g.:
        result = compute_new_result(result, A[i]);
    }
}

既计算A[i]compute_new_result相当昂贵。所以我的想法是并行计算数组元素,如果任何线程空闲,它就会开始执行顺序操作。很有可能已经计算了起始数组元素,而其他元素将由仍在执行第一个循环的其他线程提供。

但是,要使这个概念发挥作用,我必须实现两件事:

  1. 为了使 OpenMP 以另一种方式拆分循环,即用于两个线程:线程 1 计算A[0],A[2]A[4]线程 2: A[1], A[3],A[5]等。

  2. 提供一些信号系统。我正在考虑一组标志,表明A[i]已经计算过。然后在继续之前compute_new_result应该等待各自的标志被释放。A[i]

我会很高兴任何提示如何实现这两个目标。我需要能够在 Linux、Windows 和 Mac 上移植的解决方案。我正在用 C++11 编写整个代码。


编辑:

我已经找到了第一个问题的答案。看起来在指令中添加schedule(static,1)子句就足够了。#pragma omp for

但是,我仍在考虑第二个问题的优雅解决方案......

4

2 回答 2

1

如果您不介意将 OpenMP for worksharing 构造替换为生成任务的循环,则可以使用 OpenMP 任务来实现应用程序的这两个部分。

在第一个循环中,您将创建(而不是循环块)承担迭代计算负载的任务。然后,第二个循环的每次迭代也成为一个 OpenMP 任务。那么重要的部分将是在不同阶段之间同步任务。

为此,您可以使用任务依赖项(在 OpenMP 4.0 中引入):

#pragma omp task depend(out:A[0])
{ A[0] = a(); }

#pragma omp task depend(in:A[0])
{ b(A[0]); }

将确保在任务 a 完成之前任务 b 不会运行。

干杯,-迈克尔

于 2013-10-02T19:33:57.947 回答
0

这可能是扩展评论而不是答案...

所以,你有一个两阶段的计算。在第 1 阶段,您可以独立计算数组中的每个条目A。因此,使用 OpenMPparallel for循环将其并行化很简单。但是这里有一个问题,简单地将工作分配给线程可能会导致(严重?)线程之间的负载不平衡。

在第 2 阶段,有一个计算不是那么容易并行化的,您计划将其交给第一个线程以完成其在第 1 阶段的份额。

我个人将其分为两个阶段。首先,使用parallel for循环。在第二滴 OpenMP 中,只有一个顺序代码。schedule通过调整子句的参数来整理阶段 1 中的负载平衡;我很想先试试schedule(guided)

如果调整计划不能提供您想要的平衡,那么请研究用parallel for-ingtask替换。

不要通过滚动您自己的信号技术使阶段 2 的代码复杂化。我不担心复杂性会让你不知所措,尽管你可能会担心这一点,但除非你在第一阶段解决负载平衡,否则复杂性将无法带来任何好处。当你完成时你不会不需要将 phase2 放在 OpenMP 并行区域内。

于 2013-10-02T12:25:28.547 回答