【问题标题】:Recursive factorial behavior with OpenMP tasks?OpenMP 任务的递归阶乘行为?
【发布时间】:2018-05-03 09:55:24
【问题描述】:

我想知道以下代码的行为是什么。这是一个使用 OpenMP 任务并行化的简单阶乘程序。 当我运行这个程序时,我得到 0 作为输出。我知道缺少 shared(b) 子句。这是我从主要方面调用事实的方式。

#pragma omp parallel
{
    #pragma omp single nowait
    {
        fact_result = fact(4);
    }
}

这是实际的阶乘函数。

int fact(int n) {

    if(n == 0)
        return 1;

    int b = 0;

    #pragma omp task
    b = fact(n - 1);

    #pragma omp taskwait
    return n * b;

}

我不明白为什么没有 shared(b) 的结果不正确,为什么 shared(b) 的结果正确。我正在寻找这样的运行时图:

我知道一旦第 1 步完成,线程就会开始处理任务,但它们在处理什么?什么变量?他们真的在做什么吗?我们真的可以加快这样的递归计算吗?有时一棵树中有很多叶子,我们可以使用多个线程加快合并操作,但在这种情况下,最终只有 1 个叶子。如果有人能解释这段代码的行为,我真的很感激。 提前致谢。

【问题讨论】:

    标签: c openmp


    【解决方案1】:

    我不明白为什么结果不正确

    根据标准规则 2.15.1.1,任务中 b 的数据共享属性为 firstprivate

    在任务生成构造中,如果不存在默认子句,则 数据共享属性不是由 上面的规则是第一私有的。

    从逻辑上讲,您的任务如下所示:

    #pragma omp task
    {
        int n_private = n;
        int b_private = b;
        b_private = fact(n_private - 1);
    }
    

    firstprivate b 的结果只是被丢弃了。

    我们真的可以加快这样的递归计算吗?

    没有*。你没有一棵真正的树——只有一条链子。只有在树中的某些节点有多个子节点时,才能加快递归计算。

    *:如果每个节点上都有大量工作,并且该工作的某些部分不依赖于递归调用,则可以进行一些流水线操作。

    编辑:

    为什么这段代码可以通过添加一个 shared(b) 来工作

    因为fact 的结果不会被丢弃并从外部范围写入变量b

    我无法理解 taskwait 的工作方式。这真的要等待队列中的所有任务完成吗?

    它等待所有(直接)子任务完成。因为子任务也等待他们的子任务,所以在你的情况下它是传递的,即使是孙子任务。

    你可以这样想:

    | time
    V
    fact(4)
    *-----> fact(3)
    twait   *-----> fact(2)
     |      twait   *-----> fact(1)
     |       |      twait   *-----> fact(0)
     |       |       |      twait   return
     |       |       |      done  
     |       |       |      return
     |       |      done
     |       |      return
     |      done
     |      return
    done
    return
    

    如果是,那么像 b = fact(3) 这样的中间任务如何在其结果尚未解析的情况下完成(因为它的结果也在等待 taskwait!)。

    不是。

    【讨论】:

    • 感谢您的解释。你能通过在任务指令中添加一个 shared(b) 来解释为什么这段代码可以工作吗?我无法理解 taskwait 的工作方式。这真的要等待队列中的所有任务完成吗?如果是,那么像 b = fact(3) 这样的中间任务如何在其结果尚未解决的情况下完成(因为它的结果也在等待 taskwait!)。
    • 我猜 taskwait 是面向范围的。这意味着在更深范围内生成的任务正在等待 taskwait,一旦它们完成,我们将计算其他任务。我错过了什么吗?
    • @aligholamee 我在回答中添加了一些进一步的解释
    猜你喜欢
    • 1970-01-01
    • 2017-03-17
    • 2016-01-28
    • 1970-01-01
    • 2015-04-19
    • 2019-07-24
    • 2019-08-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多