Почему я получаю ошибки компоновщика во время сборки проекта C ++ AMP

0

Я пытаюсь создать систему, где мне нужна функция активатора. Эта функция активатора может иметь состояние, поэтому я попытался включить состояние в режим параллелизма :: array_view. Когда я пытаюсь построить решение, я получаю следующую ошибку компоновщика.

Ошибка 2 ошибки LNK2019: неразрешенный внешний символ "public: static double __thiscall ArtNeuroNet :: ActivationFunctions :: Activator :: function (double, class Concurrency :: array_view) ограничивает (cpu, amp)" (? Function @Activator @ActivationFunctions @ArtNeuroNet @@SENNV? $ Array_view @N $ 00 @Concurrency @@@DZ_B), на который ссылается функция _wmain D:\Projekte\ArtNeuroNet\ArtNeuroNet\ArtNeuroNet.obj ArtNeuroNet

Ошибка 3 ошибки LNK1120: 1 нерешенных внешних D:\Projekte\ArtNeuroNet\Debug\ArtNeuroNet.exe 1 1 ArtNeuroNet

Мой упрощенный активатор выглядит

double Activator::lin_function(double x, concurrency::array_view<double, 1> state)
    restrict(cpu, amp)
{
    if (x > state[StateParameterType::ThresholdParameter])
        return 1;
    else if (x < -(state[StateParameterType::ThresholdParameter]))
        return 0;
    else
        return state[StateParameterType::AlphaParameter] * x + 0.5f;
}

double* Activator::getInitialState(double alpha)
{
    double stateCpu[] = {1.0, 0.5};

    if (alpha != NULL)
        stateCpu[0] = alpha;

    return stateCpu;
}

Мое создание активатора похоже

Activator activator = *(new Activator());
double* stateCpu = activator.getInitialState(1.0);

concurrency::array_view<double, 1> state(2, stateCpu);

activator.lin_function(0.4, state);

Для целей тестирования я добавил последнюю строку, которая является активатором вызова.lin_function (0.4, state). Если я прокомментирую эту строку, проект будет создан без каких-либо проблем.

Теперь мой вопрос: что я упускаю или делаю, чего я обычно не должен делать?

РЕДАКТИРОВАТЬ

Метод lin_function является закрытым. Однако в Активаторе есть общедоступная функция метода, которая вызывает частный метод lin_function. Для упрощения я отказался от этой части исходного кода. Оба метода доступны, поскольку я иначе не смог бы построить решение, когда будет вызван вызов метода lin_function.

Активатор полностью находится в том же проекте, который сейчас является консольным приложением.

Функция lin_function опирается на одну переменную состояния. Однако пороговая реализация функции активатора вообще не нуждается в каком-либо государственном хранилище. Точно так же происходит изменение всего на функцию активации порога и комментирование остального. В частности, это означает, что "lin_function прокомментировала → отсутствие ошибки компоновщика, в противном случае → ошибка компоновщика"

EDIT 2

Для Активатора существует заголовок (Activator.h) и исходный файл (Activator.cpp). Как-то кажется, что компоновщик не может найти какой-либо метод из заголовка, объявленного как ограничение (cpu, amp).

// Doesn't get found and throws linker error
double Activator::function(double x)
    restrict(cpu, amp)
{
    return (x >= 0) ? 1 : 0;
}

// Get found and no linker errors occur
double Activator::function(double x)
{
    return (x >= 0) ? 1 : 0;
}

ИЗМЕНИТЬ 3

После определения всех методов, содержащих ограничение (amp, cpu) как статичное в header файле, все правильно построилось и бежало без проблем.

Существует ли ограничение на методы, которые должны быть статичными, когда используется ограничение (amp, cpu)?

  • 0
    Я не могу ответить на ваш вопрос, но в Activator::getInitialState вы возвращаете указатель на локальный. Не хорошая идея.
  • 0
    @Henrik: Хороший вопрос. Я изменил его, чтобы создать std :: vector <double> снаружи, и теперь передаю ссылку на вектор в метод getInitialState, где затем его значения заполняются. Однако это ничего не меняет в отношении ошибки компоновщика.
Показать ещё 3 комментария
Теги:
c++-amp

1 ответ

0
Лучший ответ

Вот ограничения на C++ AMP относительно классов и функций и т.д. Вы также ограничены подмножеством поддерживаемых типов C++, но я не думаю, что это проблема здесь.

Ссылки и указатели (на совместимый тип) могут использоваться локально, но не могут быть записаны с помощью лямбда. Указатели функций, указатель на указатель и т.д. Недопустимы; не являются статическими или глобальными переменными.

Классы должны соответствовать больше правил, если вы хотите использовать их. У них не должно быть виртуальных функций или виртуального наследования. Разрешены конструкторы, деструкторы и другие не виртуальные функции. Все переменные-члены должны быть совместимыми типами, которые, конечно, могут включать экземпляры других классов, если эти классы соответствуют тем же правилам. Фактический код в вашей совместимой с amp функции не работает на процессоре и, следовательно, не может делать определенные вещи, которые вы могли бы использовать:

  • рекурсия
  • литье
  • использование виртуальных функций
  • новый или удалить
  • RTTI или динамическое литье
  • идти к
  • бросать, пытаться или ловить
  • доступ к глобалам или статике
  • встроенный ассемблер

Это взято из моей книги, и я извиняюсь, потому что это вводит в заблуждение. Не ясно, что это относится к классам, которые вы хотите передать ядрам AMP в качестве данных. Не для классов, которые имеют restrict(amp) методы на них. Это поддерживается только для статических методов, потому что невозможно разделить класс с this указателем с GPU, поскольку он ссылается на экземпляр объекта на CPU.

Ниже приведен пример класса, который отвечает указанным выше требованиям и может быть передан ядру AMP:

class stuff
{
public:
    int a;

    stuff(int v) : a(v) { }
};

stuff также отвечает требованиям для поддерживаемых типов, поскольку int поддерживается AMP.

Следующий класс использует stuff в array_view:

class test_case
{
public:
    test_case()
    {
    }

    static int amp_method(int a) restrict(amp, cpu)
    {
        return a * a;
    };

    void test_amp()
    {
        concurrency::array_view<stuff, 1> data(100);
        concurrency::parallel_for_each(data.extent, 
            [data](concurrency::index<1> idx) restrict(amp)
        {
            data[idx].a = amp_method(data[idx].a);
        });
        data.synchronize();
    };

    void test_cpu()
    {
        std::vector<int> data(100, 0);
        for (auto& d : data)
        {
            d = amp_method(d);
        }
    }
};

Если вы удалите static модификатор на amp_method вы получите следующую ошибку на VS 2013.

предупреждение C4573: использование "test_tools_tests :: test_case :: amp_method" требует, чтобы компилятор зафиксировал this но текущий режим захвата по умолчанию не позволяет

В 2012 году вы можете увидеть что-то другое. Одной из слабых сторон первого выпуска AMP были ошибки. Это улучшилось в 2013 году.

По размышлению это кажется действительно разумным. Как я могу передать this на GPU, когда он ссылается на код, запущенный на CPU?

Обратите внимание, что restrict не может применяться к классам.

Спасибо, что выделили эту проблему. Думаю, я должен обновить информацию об ошибках.

  • 0
    Спасибо за вашу помощь в разъяснении мне ограничений C ++ AMP. Определенно необходимо, так как в настоящее время я делаю магистерскую диссертацию по созданию искусственной нейронной сети в C ++ AMP.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню