首页 > 解决方案 > openmp c ++中并行块内lambda函数的奇怪行为

问题描述

我已经开始学习 OpenMP 几天了。我遇到了这个我无法解决的错误。我定义了一个f捕获局部变量的 lambda 函数s。现在,如果我s在并行 for 循环中更改变量(每个线程的私有变量),那么该函数f不会反映其输出的变化并给出 always 0。我可以理解我在范围界定方面犯了一些错误,但找不到错误。

#include <iostream>
#include <omp.h>

int main(int argc, char *argv[])
{

    using namespace std;
    double s;
    auto f =[&]{return s;};

#pragma omp parallel for private(s)
        for(int i = 0; i < 4 ; i++)
    {
        s = 5+i;
        double a1 = f();
#pragma omp critical
        cout << a1 << endl;
    }

    return 0;
}

如果我在并行 for 循环中定义 lambda,它实际上可以工作并返回sand not的正确值0,即

#pragma omp parallel for private(s)
            for(int i = 0; i < 4 ; i++)
        {
            s = 5+i;
            double a1 = [&]{return s;}();
    #pragma omp critical
            cout << a1 << endl;
        }

我的猜测是 lambda 函数和捕获的变量需要在同一范围内。 如果 lambda 函数是在并行块之外定义的,如何解决这个问题?

标签: c++parallel-processingscopeopenmp

解决方案


您正在处理多个s变量。s(s) 中的变量parallel regions在外部范围中声明的变量。

private指令声明数据在每个线程的内存中都有一个单独的副本。因此,每个线程都将拥有自己的副本,该副本驻留在与外部作用域中声明的s内存位置不同的内存位置。sdouble s;

当您更改 in 的值时sparallel region您只是在更改 的线程本地副本s

外部范围内的值s(您ref在 a中捕获的值lambda)不会改变。外部s位于不同的内存位置。

旁注,您应该初始化外部s变量:double s{ 0 };.

// This value of x will remain unchanged.
int x = 5;

#pragma omp parallel private( x )
{
    // What happens in the `parallel block` stays in the
    // in the `parallel block`. In other words, incrementing this
    // local value of x will not change the value of x declared in the
    // outer scope. That's because this `parallel block` has its own copy of x.
    x++;      
}


// This value of x will change.
int x = 5;

#pragma omp parallel
{
    // The x variable is now shared between each thread. What you
    // do to x here changes the value of x in the outer scope.
    #pragma omp critical
    {
        x++;         
    }             
}

推荐阅读