OpenMP 中的信令

Signaling in OpenMP

本文关键字:信令 OpenMP      更新时间:2023-10-16

我正在编写计算代码,其中 more-less 具有以下原理图:

#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 编写整个代码。


编辑:

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

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

如果您不介意将用于工作共享 OpenMP 构造替换为生成任务的循环,则可以使用 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]); }

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

干杯 -迈克尔

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

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

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

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

如果调整计划无法提供所需的余额,请调查通过 task -ing 替换parallel for

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