在OpenMP中发信号

时间:2013-10-02 09:33:45

标签: c++ multithreading c++11 openmp

我正在编写的计算代码更多地具有以下原理图:

#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:{{ 1}},A[1]A[3]

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

  3. 如果有任何提示如何实现这两个目标,我会很高兴。我需要这个解决方案可以在Linux,Windows和Mac上移植。我正在用C ++ 11编写整个代码。

    <小时/> 修改

    我已经找到了第一个问题的答案。看起来向A[i]指令添加schedule(static,1)子句就足够了。

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

2 个答案:

答案 0 :(得分:1)

如果您不介意使用生成任务的循环替换OpenMP for 工作共享构造,则可以使用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没有运行。

干杯,         -Michael

答案 1 :(得分:0)

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

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

在第2阶段,有一个计算并不那么容易并行,你计划给第一个线程完成第1阶段的分享。

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

如果调整时间表无法提供您想要的余额,那么请调查parallel for替换task

不要通过滚动自己的信令技术使第2阶段的代码复杂化。我并不担心复杂情况会让你感到压力,尽管你可能会担心这一点,但除非你在第1阶段理清负荷平衡,否则并发症将无法带来任何好处。当你做完了不需要将phase2放在OpenMP并行区域内。