openmp c++ 中并行块内 lambda 函数的奇怪行为
Strange behaviour of lambda function inside parallel block in openmp c++
我开始学习OpenMP已经有几天了。我遇到了这个无法解决的错误。 我定义了一个 lambda 函数f
它捕获局部变量s
。现在,如果我在并行 for 循环中更改变量s
(每个线程的私有变量(,则函数f
不会反映其输出的变化,并且始终给出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,它实际上有效并返回s
而不是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 函数,如何解决此问题?
您正在处理多个s
变量。s
parallel region
中的变量和外部作用域中声明的s
变量。
private
指令声明数据在每个线程的内存中具有单独的副本。因此,每个线程都有自己的s
副本,该副本驻留在与外部作用域double s;
中声明的s
不同的内存位置。
当您更改parallel region
中s
的值时,您只会更改s
的线程本地副本。
外部作用域(通过lambda
中的ref
捕获(中s
的值不会更改。外部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++;
}
}
我最近经常看到人们使用捕获作为"处理"某些数据的一种方式。尽管您可以执行此操作,但捕获更通常用于访问对象的特定实例(有点像绑定(。
我认为这是"更好"(也许更通用(,如果您可以将数据作为参数传递,或者如果您想共享数据,则可以通过引用传递:
所以代替:
auto f =[&]{return s;};
你可以做:
auto f =[](double dbl){return dbl;}; // by copy
auto f =[](double &dbl){return dbl;}; // or by ref
然后像这样使用:
s = 5+i;
double a1 = f(s); // Here pass "s" into the lambda
所以,我并不是说不要使用捕获,有时这很好,但看起来你最好在这里使用参数。
相关文章:
- 可组合的lambda/std::函数与std::可选
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 如何建立使用模板函数的lambda函数的尾部返回类型
- 如何将lambda作为模板类的成员函数参数
- 我可以将调用类的"this"传递给 lambda 函数吗?
- 模板函数指针和lambda
- 两组使用lambda函数的大括号
- 尝试将lambda函数放在队列中时出现一般分配器错误(可能是与unique_ptr有关的错误)
- 我可以在这里替换什么,因为我不能在 C# 中使用隐式变量的 lambda 函数?
- 在构造函数中使用 lambda 的 C++ 类
- 如何调用存储在指向"std::函数"的指针中的 lambda?
- 为什么我不能在 constexpr lambda 函数中使用 std::tuple
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- C++:Lambda 函数指针转换的用例是什么?
- 将有状态的 lambda 传递到 C 样式函数中,而无需上下文参数
- std::映射服装比较函数和函数/lambda错误
- 在可移动类型的构造函数 lambda 中捕获此内容的安全使用
- 排序测试模板化函数 lambda:非法使用此类型作为表达式
- 将匿名函数(lambda)保存为函数类型变量
- 如何编写将自身作为回调传递的匿名函数/lambda