C++ 如何在OpenMP中减少for循环中关键部分内的值? 编辑

C++ 如何在OpenMP中减少for循环中关键部分内的值? 编辑,c++,openmp,C++,Openmp,让我们重申一切。我正在OpenMP上实现Bellman Ford。据我所知,compare步骤和dist的设置必须在关键块中完成,因为更新dist可能会改变compare步骤的结果——这里存在数据争用 我的问题是,updated\u last\u round变量不需要在关键块中更新。这里有一个数据竞争,但对值的唯一更新是true,所以这无关紧要。我对当前实现的担忧是,所有线程都在原子式地更新上次更新的updated\u\u回合,并相互减慢速度 bool compare(int v1, int w

让我们重申一切。我正在OpenMP上实现Bellman Ford。据我所知,
compare
步骤和
dist
的设置必须在关键块中完成,因为更新
dist
可能会改变
compare
步骤的结果——这里存在数据争用

我的问题是,
updated\u last\u round
变量不需要在关键块中更新。这里有一个数据竞争,但对值的唯一更新是
true
,所以这无关紧要。我对当前实现的担忧是,所有线程都在原子式地更新上次更新的
updated\u\u回合
,并相互减慢速度

bool compare(int v1, int w, int v2) {
    // checks if v1 + w < v2
    if (v1 == INT_MAX) return false;
    if (v2 == INT_MAX) return true;
    return ((v1+w) < v2);
}

vector<int> bellman_ford(Graph& g, int root) {
    vector<int> dist(g.num_nodes());
    # pragma omp parallel for
    for (int i = 0; i < g.num_nodes(); i++)
        dist[i] = INT_MAX; // set INF

    dist[root] = 0;

    int round = 0;
    bool updated_last_round = true;
    // relax procedure
    while (updated_last_round && round < g.num_nodes()) {
        updated_last_round = false;
        #pragma omp parallel for
        for (int u = 0; u < g.num_nodes(); u++) {
            vector<int> neighbors = g.out_neighbors(u);
            vector<int> weights = g.out_weights_neighbors(u);
            #pragma omp parallel for 
            for (int j = 0; j < g.out_degree(u); j++) {
                int v = neighbors[j];
                int weight = weights[j];
                #pragma omp critical
                {
                if (compare(dist[u], weight, dist[v])) { 
                    dist[v] = dist[u] + weight;
                    updated_last_round = updated_last_round || true;
                }
                }
            }
        }
        round += 1;
    }

    /* ... */

    return dist;
}
应该有一种方法可以让关键部分只做关键的事情,然后继续设置线程局部布尔值,然后在每次迭代结束时减少局部值。我应该如何做到这一点

有一种方法可以让关键部分 只做关键的事情,然后继续设置线程本地bool 值,然后在每次迭代结束时减少局部值。怎么 我应该做到这一点吗

像这样的? 在我看来,这显然是你刚才描述的实现。 我已将测试移到关键部分之外;如果没有更多的信息,我们不清楚这是否安全

bool updated_last_round = true

while (updated_last_round) {
  updated_last_round = false;

  #pragma omp parallel for reduction(||:updated_last_round)
  for (/* stuff */) {
    // other stuff
    bool updated_this_iteration = false;

    if (should_update(vars_to_decide_with)) 
     { 
       #pragma omp critical
       {
          // do the important critical update
       }
       // Set local, per-iteration, value
       updated_this_iteration = true;
    }
    updated_last_round = updated_last_round ||  updated_this_iteration;
  }
}
有一种方法可以让关键部分 只做关键的事情,然后继续设置线程本地bool 值,然后在每次迭代结束时减少局部值。怎么 我应该做到这一点吗

像这样的? 在我看来,这显然是你刚才描述的实现。 我已将测试移到关键部分之外;如果没有更多的信息,我们不清楚这是否安全

bool updated_last_round = true

while (updated_last_round) {
  updated_last_round = false;

  #pragma omp parallel for reduction(||:updated_last_round)
  for (/* stuff */) {
    // other stuff
    bool updated_this_iteration = false;

    if (should_update(vars_to_decide_with)) 
     { 
       #pragma omp critical
       {
          // do the important critical update
       }
       // Set local, per-iteration, value
       updated_this_iteration = true;
    }
    updated_last_round = updated_last_round ||  updated_this_iteration;
  }
}

首先,同时写入上一轮更新的代码在技术上仍然是一种竞争条件

但是,不要担心写入上一轮更新的
代码。与关键部分的总体开销相比,这不太重要。不要担心每个微小的内部循环迭代中的关键部分的开销。鉴于对
dist[v]
dist[u]
的读写依赖性,我看不到任何解决关键部分的方法

如何添加缩减并在关键部分内设置
updated\u last\u round
。从理论上讲,这将加快写入速度,因为它现在是本地的,而不是缓存失效的共享变量。但是,与关键部分的巨大开销相比,这也无关紧要

注意:并行化的唯一好处是如果
out_*neighbories
函数非常昂贵。但我假设它们只返回一个固定向量-出于性能原因,您应该通过
const&
返回并捕获该向量

如果您想有效地并行化此算法,您必须考虑以某种方式对数据进行分区,以解决依赖关系。小心:不幸的是,搜索“贝尔曼福特OpenMP”节目会给出一些非常不正确的尝试,例如

除此之外,不要使用嵌套并行(
parallel
内部的
parallel
,除非您真的知道自己在做什么)。并行化最外层的循环,这样做是安全的,如果它带来性能好处,则使用
collapse


在尽可能局部地声明变量方面也做得很好-这使得对竞争条件进行推理变得更加容易。这对于向量副本来说可能有点棘手-无论如何应该是
常量&

首先,同时写入
更新的最后一轮
在技术上仍然是一种竞争条件

但是,不要担心写入上一轮更新的
代码。与关键部分的总体开销相比,这不太重要。不要担心每个微小的内部循环迭代中的关键部分的开销。鉴于对
dist[v]
dist[u]
的读写依赖性,我看不到任何解决关键部分的方法

如何添加缩减并在关键部分内设置
updated\u last\u round
。从理论上讲,这将加快写入速度,因为它现在是本地的,而不是缓存失效的共享变量。但是,与关键部分的巨大开销相比,这也无关紧要

注意:并行化的唯一好处是如果
out_*neighbories
函数非常昂贵。但我假设它们只返回一个固定向量-出于性能原因,您应该通过
const&
返回并捕获该向量

如果您想有效地并行化此算法,您必须考虑以某种方式对数据进行分区,以解决依赖关系。小心:不幸的是,搜索“贝尔曼福特OpenMP”节目会给出一些非常不正确的尝试,例如

除此之外,不要使用嵌套并行(
parallel
内部的
parallel
,除非您真的知道自己在做什么)。并行化最外层的循环,这样做是安全的,如果它带来性能好处,则使用
collapse


在尽可能局部地声明变量方面也做得很好-这使得对竞争条件进行推理变得更加容易。这对于向量副本来说可能有点棘手-无论如何应该是
常量&

你不能使用
#pragma omp parallel for
同时循环。糟糕。我在发帖时更改了代码。让我快速修正一下,我不是专家,但你已经为进入关键部分付出了代价。在外部执行这一操作不会影响任何事情。只需在