OpenMp任务:不能通过引用传递参数

时间:2017-05-10 18:55:18

标签: c++ openmp undefined-reference

g++ -fopenmp main.cpp抱怨对std::vector的未定义引用。如何解决这个问题?

我在Ubuntu上安装了libomp-dev包。

的main.cpp

#include<vector>
#include<iostream>

template<typename T, typename A>
T recursiveSumBody(std::vector<T, A> &vec) {
    T sum = 0;
    #pragma omp task shared(sum)
    {
        sum = recursiveSumBody(vec);
    }
    return vec[0];
}

int main() {
    std::vector<int> a;
    recursiveSumBody(a);
    return 0;
}

未定义的参考文献

/tmp/ccTDECNm.o: In function `int recursiveSumBody<int, std::allocator<int> >(std::vector<int, std::allocator<int> >&) [clone ._omp_cpyfn.1]':
main.cpp:(.text+0x148): undefined reference to `std::vector<int, std::allocator<int> >::vector(std::vector<int, std::allocator<int> > const&)'
collect2: error: ld returned 1 exit status

2 个答案:

答案 0 :(得分:4)

要解决此问题,您可以手动指定shared(sum, vec)(强烈假设您希望它共享)。

有趣的是,较旧的gcc版本(例如5.4.0)提供了更有用的错误消息:

error: 'vec' implicitly determined as 'firstprivate' has reference type

英特尔编译器icpc 17.0.1提供“internal error : 0_1855”。

手动指定firstprivateprivate - 这在您的情况下毫无意义 - 会导致其他更具描述性的错误。请注意,正如Hristo Iliev在其他评论中所解释的那样,firstprivate意味着为每个线程创建了一个向量副本。

根据目前的(4.5)标准:

  

在孤立的任务生成构造中,如果不存在默认子句,则通过引用传递的正式参数为firstprivate

我想这适用于此。此外,

  

firstprivate子句中出现的变量不能包含不完整的C / C ++类型,也不能是对不完整类型的引用。   如果工作共享构造的firstprivate子句中的列表项具有引用类型,则它必须绑定到团队的所有线程的同一对象。

它没有出现在一个条款中,但我认为这仍然是标准的含义。

现在我认为std::vector<T, A>在模板中不是一个不完整的类型,除非我遗漏了一些关于如何实例化模板的内容。所以我认为你的代码应该是有效的,并且假设每个线程只绑定到同一个对象,它实际上是有意义的。

所以我认为这是最近的gcc版本以及英特尔编译器中的错误。看起来编译器无法为模板实例化一些东西。

此外,添加:

if (0) std::vector<T, A> wtf = vec;

在函数的开头使代码编译并与gcc链接。但如果手动添加firstprivate,gcc会继续抱怨'vec' has incomplete type

P.S。:在OpenMP 4.5中添加了允许数据共享属性子句中的引用类型,这是旧的gcc给出了不同的错误。

答案 1 :(得分:1)

如果您还将vec声明为共享变量,问题就会消失:

#pragma omp task shared(sum, vec)

似乎task的默认可见性为firstprivate,未按预期分享。您可以在this forum entry中找到更多信息。