我对以下任务有疑问:
“给定一个二维数组“a[N][M]”,所以 N 行长度为 M。数组的每个元素包含一个 0 到 16 之间的随机整数值。写一个内核“compact(int *a, int * listM, int *listN)" 只包含一个N 个线程块,每个线程计算数组的一行有多少元素的值为 16。
线程将这些数字写入共享内存中长度为 N 的数组“num”,然后(在屏障之后)其中一个线程执行下面列出的前缀代码“PrefixSum(int *num, int N)”(在代码中下面我解释一下这段代码的作用)。最后(再次障碍),每个线程“Idx”将其行中值为 16 的元素的 N 值和 M 值,分别位置(或“x 和 y 坐标”)写入两个数组中“全局内存中的 listM" 和 "listN",从这些数组中的位置 "num[Idx]" 开始。为了更容易实现这最后一个任务,有上面提到的前缀代码。”
我已经编写了一个内核和一个合适的 main 来测试它。但是,我仍然有一个我无法解决的问题。
在两个数组“listeM”和“listeN”中,应该存储出现在数组“a[M][N]”中的每个 16 的单独位置。因此,它们的大小必须等于 16 的出现总数,这可能会有所不同。
由于您不知道值为 16 的元素的确切数量,因此您只能在内核运行时知道两个数组“listeM”和“listeN”需要多少内存。当然,您可以在程序启动时为最大可能数量释放足够的内存,即 N 乘以 M,但这将非常低效。是否可以编写内核,以便每个线程在计算其行中值为 16 的元素数量(仅此数字)之后动态扩大两个数组“listeM”和“listeN”?
这是我的内核:
__global__ void compact(int* a, int* listM, int* listN)
{
int Idx = threadIdx.x;
int elements, i;
i = elements = 0;
__shared__ int num[N];
for (i = 0; i < M; i++)
{
if (a[Idx][i] == 16)
{
elements++;
}
}
num[Idx] = elements;
//Here at this point, the thread knows the number of elements with the value 16 of its line and would
//need to allocate just as much extra memory in "listeM" and "listeN". Is that possible ?
__syncthreads();
if (Idx == 0)
{
//This function sets the value of each element in the array "num" to the total value of the
//elements previously counted in all lines with the value 16.
//Example: Input: num{2,4,3,1} Output: num{0,2,6,9}
PrefixSum(num, N);
}
__syncthreads();
// The output of PrefixSum(num, N) can now be used to realize the last task (put the "coordinates" of
//each 16 in the two arrays ("listM" and "listN") and each thread starts at the position equal the
//number of counted 16s).
for (i = 0; i < M; i++)
{
if (a[Idx][i] == 16)
{
listM[num[Idx] + i] = Idx;
listN[num[Idx] + i] = i;
}
}
}