在C ++ AMP的parallel_for_each中使用用户指定的函数

时间:2014-07-23 10:22:59

标签: c++ templates c++11 concurrency c++-amp

我目前正在编写库,我希望能够允许用户定义一个函数(声明为restrict( amp ))并允许他们将此函数传递给我的一个库函数在concurrency::parallel_for_each循环中使用。例如:

template <typename T, typename Func>
void Foo( const concurrency::array_view<const T>& avParam, Func f ) 
{
     concurrency::array<T, 1> arrResult( avParam.extent );
     concurrency::parallel_for_each( avParam.extent, [=, &arrResult]( concurrency::index<1> index ) restrict(amp) {
          arrResult[index] = f( avParam[index] );
     } );

     // Do stuff...
}

我希望这可以工作,提供f被声明为有效的AMP兼容函数,就像我直接用函数本身替换函数指针f一样;一切都按预期工作。但是,使用f会导致以下错误:

  

不支持函数指针,函数引用或指向成员函数的指针。

在没有阻止我的用户使用除lambdas之外的仿函数的情况下,我有什么方法可以获得我想要的行为吗?

3 个答案:

答案 0 :(得分:2)

  

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

     

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

     
      
  • 递归
  •   
  • 指针转换
  •   
  • 使用虚拟功能
  •   
  • new或delete
  •   
  • RTTI或动态投射
  •   

您应该根据仿函数的lambdas编写库,因为可以使用restrict(amp)内核访问它们。您可以执行以下操作:

template <typename T, typename Func>
void Foo(const concurrency::array_view<const T>& avParam, Func f)
{
    concurrency::array<T, 1> arrResult(avParam.extent);
    concurrency::parallel_for_each(avParam.extent, [=, &arrResult](concurrency::index<1> index) restrict(amp) 
    {
        arrResult[index] = f(avParam[index]);
    });

    // Do stuff...
}

template <typename T>
class Bar
{
public:
    T operator()(const T& v) const restrict(amp)
    {
        return v + 2;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    std::vector<int> result(100, 0);
    array_view<const int, 1> result_av(result.size(), result);

    Foo(result_av, Bar<int>());

    return 0;
}

考虑这一点的一种方法是functor或lambda等效创建一个容器,编译器可以确保它没有依赖关系,并且C ++ AMP运行时可以在GPU上实例化。使用函数指针实现这一点要困难得多。

答案 1 :(得分:0)

我这里没有窗框,所以无法复制或测试。

  

不支持函数指针,函数引用或指向成员函数的指针。

这意味着

  • 一个函数指针&#39; pf&#39;喜欢在&#39; R (*pf) (T)必须至少包含std::function<R(T)> func(pf)

  • func传递调用堆栈到函数[{1}}

  • 无论如何,
  • 和mem_fun_pt都已关闭。

从[SKJJ12]第9页我认为那个函数,以及调用堆栈中的所有函数或函数对象,也需要标记为std::forward<std::function<R(T)>>(in_func)并实现该概念。

in_func

答案 2 :(得分:0)

假设我们有:

template <typename T, typename Func>
void Foo( const concurrency::array_view<const T>& avParam, Func f ) 

int f(int x) restrict(amp) {return x+2;}

然后尝试:

Foo( avParam, [](int x) restrict(amp){ return f(x); } );`

而不是指向f的函数指针,而是创建一个不使用函数指针的lambda。

我们可以自动化

#define AMP_OVERLOAD_SET(F) struct { \
  template<typename... Args> auto operator()(Args&&...args)const restrict(amp) \
  ->decltype( F(std::declval<Args>()...) ) \
  { return F( std::forward<Args>(args)... ); } \
}

static AMP_OVERLOAD_SET(f) amped_f; // declare an overload set object for `f`
Foo( vParam, amped_f ); // pass it to `Foo`

可能有效也可能无效。