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

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

Ошибка 2 ошибка LNK2019: неразрешенный внешний символ "public: static double __thiscall ArtNeuroNet::ActivationFunctions::Activator::function(double,class Concurrency::array_view) limited(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);

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

Мой вопрос в том, что я упускаю или делаю то, что на самом деле не должен делать?

ИЗМЕНИТЬ

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

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

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

ИЗМЕНИТЬ 2

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

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

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

ИЗМЕНИТЬ 3

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

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


person fschaeffler    schedule 29.01.2014    source источник
comment
Я не могу ответить на ваш вопрос, но в Activator::getInitialState вы возвращаете указатель на локальный. Не хорошая идея.   -  person Henrik    schedule 29.01.2014
comment
@ Хенрик: Хороший вопрос. Я изменил его, чтобы создать std::vector‹double› снаружи, и теперь передаю ссылку на вектор методу getInitialState, где затем заполняются его значения. Однако это ничего не меняет в отношении ошибки компоновщика.   -  person fschaeffler    schedule 29.01.2014
comment
Я не думаю, что это ошибка, связанная с C++ AMP. И мне нужно больше информации, чтобы отследить его. Вещи, которые приходят на ум; является общедоступной lin_function? Активатор импортирован из другого проекта с другим соглашением о вызовах и т. д.? Что произойдет, если вы удалите параметр array_view из lin_function, это работает?   -  person Ade Miller    schedule 30.01.2014
comment
ХОРОШО. Так что это полностью AMP вещь. Я понятия не имею, почему это получило отрицательный голос. Вполне резонный вопрос. Какую версию VS вы используете 2012 или 13? Это повлияет на ошибки, которые вы видите. Смотрите мой полный ответ ниже.   -  person Ade Miller    schedule 31.01.2014
comment
Моя среда разработки — Visual Studio 2013, Windows 8.1 64 Bit и NVIDIA GeForce GTX 770.   -  person fschaeffler    schedule 31.01.2014


Ответы (1)


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

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

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

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

Это взято из моей книги, и я прошу прощения, потому что это вводит в заблуждение. Что не ясно, так это то, что это относится к классам, которые вы хотите передать ядрам AMP в качестве данных. Не для классов, у которых есть restrict(amp) методы. Это поддерживается только для статических методов, поскольку невозможно совместно использовать указатель класса this с графическим процессором, поскольку он ссылается на экземпляр объекта в ЦП.

Итак, ниже приведен пример класса, который соответствует вышеуказанным требованиям и может быть передан ядру 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 графическому процессору, если он относится к коду, работающему на процессоре?

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

Спасибо за освещение этой проблемы. Я предполагаю, что я должен обновить книгу опечаток.

person Ade Miller    schedule 31.01.2014
comment
Спасибо за вашу помощь в разъяснении мне ограничений C++ AMP. Определенно нужен, так как сейчас я работаю над магистерской диссертацией по созданию искусственной нейронной сети на C++ AMP. - person fschaeffler; 31.01.2014