c++ - std::generate_n 的并行执行可变 lambda 生成器

标签 c++ lambda parallel-processing c++17

当使用在其捕获中具有初始化程序的可变 lambda 对 std::generate_n 使用并行执行时,并行访问初始化值是否线程安全?

[MCVE]

#include<vector>
#include <algorithm>
#include <execution>

int main()
{
  std::vector<int> v(1000);
  std::generate_n(std::execution::par, v.data(), v.size(), [i = 0]() mutable { return i++; });

  return 0;
}

访问捕获的 i 是线程安全的吗?

最佳答案

首先我们来看一下generate_n的签名:

template< class ExecutionPolicy, class ForwardIt , class Size, class Generator >
ForwardIt generate_n(ExecutionPolicy&& policy, ForwardIt first, Size count, Generator g);

重要的是最后一个参数(它是您的 lambda)是按值传递的。此外,您不知道它是如何在实现中内部传递的,因此您的 lambda 可能有一些拷贝,并且每个拷贝都有自己的计数器。我想这不是本意。

有几个选项可以在实例之间共享计数器:

  1. 在 lambda 上使用 std::ref:

    const auto func = [i = std::atomic<int>()]() mutable -> int {  
    return i++; };
    std::vector<int> v(1000);
    std::generate_n(std::execution::par, v.data(), v.size(), std::ref(func));
    
  2. 仿函数实例之间的共享计数器:

    std::atomic<int> i = 0;
    std::vector<int> v(1000);
    std::generate_n(std::execution::par, v.data(), v.size(), [&i]() -> int { return i++; });
    

请注意,在这两种情况下我都使用了 std::atomic,因为您需要自己处理同步。

关于c++ - std::generate_n 的并行执行可变 lambda 生成器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55590503/

相关文章:

Java 8 方法引用多个不同的构造函数

c# - EF 扩展 AddIfNotExists 本地 lambda

matlab - 如何在 MATLAB 中并行化输入和显示?

c++ - 如何获取 GDI 句柄列表

ruby - block 第一次不识别变量

.net - Visual C++ 编译器错误 2061

c# - 通过异步示例了解 C# 中的并行编程

performance - Haskell 并行运行速度较慢

c++ - Box2D:如何让物体忽略重力

c++ - 不同的对象指针值及其this指针