1

我尝试制作一个需要激活器功能的系统。这个激活器函数可能有状态,所以我尝试将状态放入一个concurrency::array_view。当我尝试构建解决方案时,我收到以下链接器错误。

错误 2 错误 LNK2019:无法解析的外部符号“public: static double __thiscall ArtNeuroNet::ActivationFunctions::Activator::function(double,class Concurrency::array_view) restrict(cpu, amp)”(?function@Activator@ActivationFunctions@ArtNeuroNet@ @SENNV?$array_view@N$00@Concurrency@@@ DZ _B) 在函数 _wmain D:\Projekte\ArtNeuroNet\ArtNeuroNet\ArtNeuroNet.obj ArtNeuroNet 中引用

错误 3 error LNK1120: 1 unresolved externals 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 是私有的。但是,在 Activator 中有一个公共方法函数,它调用私有方法 lin_function。出于简化的原因,我将源代码的那部分排除在外。这两种方法都是可访问的,否则当对方法 lin_function 的调用被注释掉时,我将无法构建解决方案。

Activator 完全位于同一个项目中,该项目目前是一个控制台应用程序。

lin_function 依赖于单个状态变量。但是,激活函数的阈值实现根本不需要任何状态存储。将所有内容更改为阈值激活函数并将其余部分注释掉的反应方式相同。特别是“lin_function 已注释掉 -> 没有链接器错误,否则 -> 链接器错误”</p>

编辑 2

对于 Activator,存在一个标头 (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)的方法定义为静态后,一切都正确构建并且运行没有问题。

当使用 restrict(amp, cpu) 时,实际上是否对需要静态的方法有限制?

4

1 回答 1

1

以下是 C++ AMP 在类和函数等方面的限制。您也仅限于受支持的 C++ 类型的子集,但我认为这不是问题所在。

引用和指针(指向兼容类型)可以在本地使用,但不能被 lambda 捕获。不允许使用函数指针、指针到指针等;既不是静态变量也不是全局变量。

如果您希望使用它们的实例,类必须满足更多规则。它们必须没有虚函数或虚继承。允许使用构造函数、析构函数和其他非虚拟函数。成员变量必须都是兼容的类型,当然可以包括其他类的实例,只要这些类符合相同的规则。您的 amp 兼容函数中的实际代码未在 CPU 上运行,因此无法执行您可能习惯执行的某些操作:

  • 递归
  • 指针铸造
  • 使用虚函数
  • 新建或删除
  • RTTI 或动态转换
  • 投掷、尝试或抓住
  • 访问全局变量或静态变量
  • 内联汇编器

这是从我的书中摘录的,我很抱歉,因为它具有误导性。尚不清楚的是,这适用于您希望作为数据传递给 AMP 内核的类。不是对它们有restrict(amp)方法的类。这仅支持静态方法,因为无法this与 GPU 共享类指针,因为它引用 CPU 上的对象实例。

所以下面是一个满足上述要求并且可以传递给 AMP 内核的类的示例:

class stuff
{
public:
    int a;

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

stuff还满足intAMP 支持的受支持类型的要求。

以下类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当它指代在 CPU 上运行的代码时,我怎么能传递给 GPU?

请注意,restrict不能应用于类。

感谢您强调这个问题。我想我应该更新这本书的勘误表。

于 2014-01-31T06:30:23.937 回答