C++ 结构中的CUDA设备函数指针没有静态指针或符号副本

C++ 结构中的CUDA设备函数指针没有静态指针或符号副本,c++,cuda,gpu,C++,Cuda,Gpu,如果可能的话,我的计划流程如下所示: typedef struct structure_t { [...] /* device function pointer. */ __device__ float (*function_pointer)(float, float, float[]); [...] } structure; [...] /* function to be assigned. */ __device__ float my_function (float a,

如果可能的话,我的计划流程如下所示:

typedef struct structure_t
{
  [...]
  /* device function pointer. */
  __device__ float (*function_pointer)(float, float, float[]);
  [...]
} structure;

[...]

/* function to be assigned. */
__device__ float
my_function (float a, float b, float c[])
{
  /* do some stuff on the device. */
  [...]
}

void
some_structure_initialization_function (structure *st)
{
  /* assign. */
  st->function_pointer = my_function;
  [...]
}
这是不可能的,并且在编译过程中,由于在结构中放置_device _uu而导致了一个常见的错误

 error: attribute "device" does not apply here
 error: attribute "device" does not apply here
这里有一些关于stackoverflow的类似问题的例子,但它们都涉及在结构外部使用静态指针。例如和。我以前在其他代码中也采用了类似的方法,在这些代码中,我很容易使用静态设备指针,并在任何结构之外定义它们。目前,这是一个问题。它是作为某种API编写的,用户可以定义一个、两个或几十个需要包含设备函数指针的结构。因此,在结构外部定义静态设备指针是一个主要问题

我相当肯定,通过使用符号副本,我在上面链接的帖子中找到了答案,但我无法成功地使用它们。

您试图做的是可能的,但是您在声明和定义将保存和使用函数指针的结构时犯了一些错误

这是不可能的,并在编译过程中以一个熟悉的错误结束 关于在结构中放置_装置_

 error: attribute "device" does not apply here
 error: attribute "device" does not apply here
这只是因为您试图将内存空间分配给结构或类数据成员,这在CUDA中是非法的。定义或实例化类时,隐式设置所有类或结构数据成员的内存空间。所以有些东西只是略微不同(而且更具体):

您将得到一个完全可编译且可运行的示例。这里有两个
\uuuuuuu设备
函数和一个静态函数表,为主机代码在运行时检索
\uuuu设备
函数指针提供了一种机制。每个
\uuuu device\uuuu
函数调用内核一次,并显示结果,以及从主机代码实例化和调用的完全相同的functor和函数(因此在主机上运行)以进行比较:

$ nvcc -arch=sm_30 -Xptxas="-v" -o function_pointer function_pointer.cu 

ptxas info    : Compiling entry function '_Z6kernelffPFfff6float4EPKS_Pfi' for 'sm_30'
ptxas info    : Function properties for _Z6kernelffPFfff6float4EPKS_Pfi
    16 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info    : Function properties for _Z2f1ff6float4
    24 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info    : Function properties for _Z2f2ff6float4
    24 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info    : Used 16 registers, 356 bytes cmem[0], 16 bytes cmem[3]

$ ./function_pointer 
 0      1      2 (     0,     1,     2,     3 )     13     13      9      9
 1      1      2 (     4,     5,     6,     7 )     45     45     25     25
 2      1      2 (     8,     9,    10,    11 )     77     77     41     41
 3      1      2 (    12,    13,    14,    15 )    109    109     57     57
 4      1      2 (    16,    17,    18,    19 )    141    141     73     73
 5      1      2 (    20,    21,    22,    23 )    173    173     89     89
 6      1      2 (    24,    25,    26,    27 )    205    205    105    105
 7      1      2 (    28,    29,    30,    31 )    237    237    121    121
 8      1      2 (    32,    33,    34,    35 )    269    269    137    137
 9      1      2 (    36,    37,    38,    39 )    301    301    153    153
10      1      2 (    40,    41,    42,    43 )    333    333    169    169
11      1      2 (    44,    45,    46,    47 )    365    365    185    185
12      1      2 (    48,    49,    50,    51 )    397    397    201    201
13      1      2 (    52,    53,    54,    55 )    429    429    217    217
14      1      2 (    56,    57,    58,    59 )    461    461    233    233
15      1      2 (    60,    61,    62,    63 )    493    493    249    249
16      1      2 (    64,    65,    66,    67 )    525    525    265    265
17      1      2 (    68,    69,    70,    71 )    557    557    281    281
18      1      2 (    72,    73,    74,    75 )    589    589    297    297
19      1      2 (    76,    77,    78,    79 )    621    621    313    313
如果我正确理解了您的问题,那么上面的示例将为您提供在设备代码中实现您的想法所需的几乎所有设计模式。

您尝试的是可能的,但是,在声明和定义将保存和使用函数指针的结构时,您犯了一些错误

这是不可能的,并在编译过程中以一个熟悉的错误结束 关于在结构中放置_装置_

 error: attribute "device" does not apply here
 error: attribute "device" does not apply here
这只是因为您试图将内存空间分配给结构或类数据成员,这在CUDA中是非法的。定义或实例化类时,隐式设置所有类或结构数据成员的内存空间。所以有些东西只是略微不同(而且更具体):

您将得到一个完全可编译且可运行的示例。这里有两个
\uuuuuuu设备
函数和一个静态函数表,为主机代码在运行时检索
\uuuu设备
函数指针提供了一种机制。每个
\uuuu device\uuuu
函数调用内核一次,并显示结果,以及从主机代码实例化和调用的完全相同的functor和函数(因此在主机上运行)以进行比较:

$ nvcc -arch=sm_30 -Xptxas="-v" -o function_pointer function_pointer.cu 

ptxas info    : Compiling entry function '_Z6kernelffPFfff6float4EPKS_Pfi' for 'sm_30'
ptxas info    : Function properties for _Z6kernelffPFfff6float4EPKS_Pfi
    16 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info    : Function properties for _Z2f1ff6float4
    24 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info    : Function properties for _Z2f2ff6float4
    24 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info    : Used 16 registers, 356 bytes cmem[0], 16 bytes cmem[3]

$ ./function_pointer 
 0      1      2 (     0,     1,     2,     3 )     13     13      9      9
 1      1      2 (     4,     5,     6,     7 )     45     45     25     25
 2      1      2 (     8,     9,    10,    11 )     77     77     41     41
 3      1      2 (    12,    13,    14,    15 )    109    109     57     57
 4      1      2 (    16,    17,    18,    19 )    141    141     73     73
 5      1      2 (    20,    21,    22,    23 )    173    173     89     89
 6      1      2 (    24,    25,    26,    27 )    205    205    105    105
 7      1      2 (    28,    29,    30,    31 )    237    237    121    121
 8      1      2 (    32,    33,    34,    35 )    269    269    137    137
 9      1      2 (    36,    37,    38,    39 )    301    301    153    153
10      1      2 (    40,    41,    42,    43 )    333    333    169    169
11      1      2 (    44,    45,    46,    47 )    365    365    185    185
12      1      2 (    48,    49,    50,    51 )    397    397    201    201
13      1      2 (    52,    53,    54,    55 )    429    429    217    217
14      1      2 (    56,    57,    58,    59 )    461    461    233    233
15      1      2 (    60,    61,    62,    63 )    493    493    249    249
16      1      2 (    64,    65,    66,    67 )    525    525    265    265
17      1      2 (    68,    69,    70,    71 )    557    557    281    281
18      1      2 (    72,    73,    74,    75 )    589    589    297    297
19      1      2 (    76,    77,    78,    79 )    621    621    313    313

如果我正确理解了您的问题,上面的示例将为您提供在设备代码中实现您的想法所需的几乎所有设计模式。

非常感谢您的详细回答。这给了我在代码中实现想法所需的一切。已经开始运行了。我会接受这个答案。为什么你删除了C标签?因为这是一个C++问题。尽管被标记为“CUDA C”,但是设备语言实际上是C++的子集。主机和设备代码都是用C++编译器编译的,结构、指针和函数的语义遵循C++惯例。这很好,但是我的代码完全是C,而且我的问题中没有C++。我想,如果说它应该同时具备这两个方面的话,那么它的基本原理是相当直截了当的。你看一下你问题中的那些结构,看到“普通C”。用于编译它的工具链是C++,并且只包含数据成员的C++结构。您抱怨的语法错误的原因是因为C++语义应用于那些数据成员。当您编写代码并使用CUDA工具链编译时,您正在编写C++代码,不管您是否意识到。非常感谢您的详细答复。这给了我在代码中实现想法所需的一切。已经开始运行了。我会接受这个答案。为什么你删除了C标签?因为这是一个C++问题。尽管被标记为“CUDA C”,但是设备语言实际上是C++的子集。主机和设备代码都是用C++编译器编译的,结构、指针和函数的语义遵循C++惯例。这很好,但是我的代码完全是C,而且我的问题中没有C++。我想,如果说它应该同时具备这两个方面的话,那么它的基本原理是相当直截了当的。你看一下你问题中的那些结构,看到“普通C”。用于编译它的工具链是C++,并且只包含数据成员的C++结构。您抱怨的语法错误的原因是因为C++语义应用于那些数据成员。当您编写代码并使用CUDA工具链编译时,您是否正在编写C++代码,不管您是否意识到。