如何在循环内将大对象复制到omp任务?

kae*_*gre 5 c++ openmp

我正在使用while循环来启动几个omp任务。每个任务都需要复制一个相当大的对象(作为第一个私有对象)。由于我的设置,大对象(在此示例中为矢量)将被天真地复制两次:

struct bigStruct {
    bool next() {
        /* do something with m_bigVector */
    }

    std::vector<int> m_bigVector;
    /* other (big) data members */
};

bigStruct s;

#pragma omp parallel
{
    #pragma omp single
    while (s.next()) {
        auto obj = s.m_bigVector; //copy the first time

        #pragma omp task firstprivate(obj) //copy the second time
        {
            /* do something with obj */
        }
    }
} //end parallel
Run Code Online (Sandbox Code Playgroud)

gcc优化(-O3)似乎并没有以任何方式优化两个复制步骤。一个(不太优雅的)解决方案是使用显式的new/delete

#pragma omp parallel
{
    #pragma omp single
    while (s.next()) {
        auto obj_ptr = new std::vector<int>(s.m_bigVector); //copy once

        #pragma omp task firstprivate(obj_ptr) //copy only the pointer
        {
            /* do something with obj */


            delete obj_ptr; 
        }
    }
} //end parallel
Run Code Online (Sandbox Code Playgroud)

还有modern/elegant解决这个问题的方法吗?也许是一种告诉任务移动对象而不是复制对象的方法?请注意,我不想复制整体,bigStruct因为它包含其他大数据成员。

Zul*_*lan 2

好消息!

\n\n
\n

FirstPrivate 变量不得具有引用类型。

\n
\n\n

自 OpenMP 4.5 (2015) 起已过时。目前没有这样的限制。有一个要求:

\n\n
\n

如果工作共享构造上的子句中的列表项firstprivate具有引用类型,则它必须绑定到团队的所有线程的同一对象。

\n
\n\n

但这并不适用 - 该task构造不是工作共享构造,并且无论如何都不会被多个线程遇到。

\n\n

要充分了解该标准的要求:

\n\n

(关于清单项目私有化)

\n\n
\n

如果列表项的类型是对类型的引用T,则该类型将被视为用于T本子句的所有目的。

\n\n

为构造分配具有自动存储持续时间的相同类型的新列表项。\n 这些列表项的存储和生命周期将持续到创建它们的块退出为止。

\n\n

对于类类型的每个变量:

\n\n

\xe2\x80\xa2 如果该firstprivate子句不在target构造上,则调用复制构造函数来执行初始化

\n
\n\n

所以您可以安全地执行以下操作:

\n\n
auto& obj = s.m_bigVector;\n#pragma omp task firstprivate(obj) // call copy ctor once\n
Run Code Online (Sandbox Code Playgroud)\n\n

不幸的是你不能

\n\n
    \n
  • 使用const auto&是因为这样 的类型obj将是 const,因为仅删除了引用。
  • \n
  • 将 obj 移至firstprivate声明中。这很好,但仅适用于只有单个线程实际遇到数据共享子句的任务。
  • \n
\n