Я пытаюсь создать систему, где мне нужна функция активатора. Эта функция активатора может иметь состояние, поэтому я попытался включить состояние в режим параллелизма :: 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)?
Вот ограничения на 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
не может применяться к классам.
Спасибо, что выделили эту проблему. Думаю, я должен обновить информацию об ошибках.
Activator::getInitialState
вы возвращаете указатель на локальный. Не хорошая идея.