CUDA: ошибка LNK2005 в функции __device__, используемой в заголовочном файле - PullRequest
7 голосов
/ 14 марта 2011

У меня есть устройство , которое определено в заголовочном файле. Причина, по которой он находится в заголовочном файле, заключается в том, что он используется ядром global , которое должно находиться в заголовочном файле, поскольку это ядро ​​шаблона.

Когда этот заголовочный файл включен в 2 или более файлов .cu, я получаю ошибку LNK2005 во время компоновки:

FooDevice.cu.obj: ошибка LNK2005: "int __cdecl getCurThreadIdx (void) "(? getCurThreadIdx @@ YAHXZ) уже определено в Main.cu.obj

Почему эта ошибка вызвана? Как это исправить?

Вот пример кода для выдачи вышеуказанной ошибки:

FooDevice.h:

#ifndef FOO_DEVICE_H
#define FOO_DEVICE_H

__device__ int getCurThreadIdx()
{
    return ( ( blockIdx.x * blockDim.x ) + threadIdx.x );
}

template< typename T >
__global__ void fooKernel( const T* inArr, int num, T* outArr )
{
    const int threadNum = ( gridDim.x * blockDim.x );

    for ( int idx = getCurThreadIdx(); idx < num; idx += threadNum )
        outArr[ idx ] = inArr[ idx ];

    return;
}

__global__ void fooKernel2( const int* inArr, int num, int* outArr );

#endif // FOO_DEVICE_H

FooDevice.cu:

#include "FooDevice.h"

// One other kernel that uses getCurThreadIdx()
__global__ void fooKernel2( const int* inArr, int num, int* outArr )
{
    const int threadNum = ( gridDim.x * blockDim.x );

    for ( int idx = getCurThreadIdx(); idx < num; idx += threadNum )
        outArr[ idx ] = inArr[ idx ];

    return;
}

Main.cu:

#include "FooDevice.h"

int main()
{
    int num             = 10;
    int* dInArr         = NULL;
    int* dOutArr        = NULL;
    const int arrSize   = num * sizeof( *dInArr );

    cudaMalloc( &dInArr, arrSize );
    cudaMalloc( &dOutArr, arrSize );

    // Using template kernel
    fooKernel<<< 10, 10 >>>( dInArr, num, dOutArr );

    return 0;
}

Ответы [ 2 ]

7 голосов
/ 14 марта 2011

Почему эта ошибка вызвана?

Поскольку вы включили свой заголовок в FooDevice.cu и Main.cu, где он определен, теперь у вас есть две копии одной и той же функции, и компоновщик обнаруживает это.

Как это исправить?

Если в foo.h определено следующее:

template<typename T> __device__ T foo(T x)
{
    return x;
}

И два файла .cu, оба из которых содержат foo.h и также содержатпозвоните ему, например,

int x = foo<int>(1);

Затем вы можете принудительно включить foo ():

template<typename T>
inline __device__ T foo(T x)
{
    return x;
}

и позвонить:

int x = foo<int>(1);

Это остановит егообъявляется несколько раз.

Шаблоны функций освобождены от одного правила определения и могут содержать несколько определений в разных единицах перевода.Полнофункциональная специализация шаблона - это не шаблон, а обычная функция, поэтому вам нужно использовать встроенное ключевое слово, чтобы не нарушать ODR, если вы хотите поместить их в заголовочный файл, включенный в несколько единиц перевода.

Взято из http://www.velocityreviews.com/forums/t447911-why-does-explicit-specialization-of-function-templates-cause-generation-of-code.html

См. Также: http://en.wikipedia.org/wiki/One_Definition_Rule

Я изменил ваш код следующим образом:

inline __device__ int getCurThreadIdx()
{
    return ( ( blockIdx.x * blockDim.x ) + threadIdx.x );
}

template< typename T >
__global__ void fooKernel( const T* inArr, int num, T* outArr )
{
    const int threadNum = ( gridDim.x * blockDim.x );

    for ( int idx = getCurThreadIdx(); idx < num; idx += threadNum )
        outArr[ idx ] = inArr[ idx ];

    return;
}

И теперь он компилируется.Ваше объявление без встроенного getCurThreadIdx () нарушало правило одного определения.

0 голосов
/ 14 марта 2011

Это должно быть встроенным. Вы можете попробовать добавить ключевое слово inline.

Может быть, вы могли бы удалить ненужный код и создать простой текстовый пример, который мы увидим? Обычно проблема кроется в деталях ...

...