我遇到了一些问题当在推力库中使用函数时,我不确定是否应该在它之前手动添加cudaDeviceSynchronize。例如,
double dt = 0;
kernel_1<<<blocks, threads>>>(it);
dt = *(thrust::max_element(it, it + 10));
printf("%f\n", dt);
由于kernel_1是非阻塞的,因此host将执行下一个语句。问题是我不确定thrust :: max_element是否阻塞。如果它是阻塞的,那么它运作良好;否则,主持人会跳过它并执行“printf”语句吗?
由于
答案 0 :(得分:2)
您的代码至少有两种方式破解。
it
可能是设备指针:
kernel_1<<<blocks, threads>>>(it);
^^
不允许使用原始设备指针作为推力算法的参数:
dt = *(thrust::max_element(it, it + 10));
^^
除非您将该指针包装在thrust::device_ptr
中,否则将thrust::device
执行策略显式地用作算法的参数。如果没有任何这些线索,推力将调度主机代码路径(可能会出现故障),如thrust quick start guide中所述。
如果使用thrust::device_ptr
或thrust::device
修复了上述项目,则thrust::max_element
will return an iterator的类型与传递给它的迭代器一致。如果您传递thrust::device_ptr
,则会返回thrust::device_ptr
。如果对原始指针使用thrust::device
,它将返回原始指针。在任何一种情况下,在主机代码中取消引用是非法的:
dt = *(thrust::max_element(it, it + 10));
^
再次,我希望这样的用法可以解决错误。
关于异步,可以安全地假设返回存储在堆栈变量中的标量的所有推力算法都是同步的。这意味着CPU线程将不会超出推力调用,直到堆栈变量填充了正确的值
关于GPU活动,除非您使用流,否则所有GPU活动都会发布到相同(默认)流。这意味着所有CUDA活动都将按顺序执行,并且在前面的CUDA活动完成之前,不会开始给定的CUDA操作。因此,即使您的内核启动是异步的,并且CPU线程将继续进行thrust::max_element
调用,从该调用产生的任何CUDA活动都不会开始执行,直到上一次内核启动完成为止。因此,在it
开始任何CUDA处理之前,kernel_1
thrust::max_element
引用的数据所做的任何更改都应完成并完全有效。正如我们所见,thrust::max_element
本身将插入同步。
因此,一旦修复了代码中的缺陷,就不需要在任何地方插入额外的同步。
答案 1 :(得分:0)
此功能似乎不是异步。
这两个页面都解释了max_element()的行为,并且它们没有将它显式为async,所以我认为它是阻塞的:
因为它使用迭代器来处理所有元素并找到值的最大值,所以我不能认为它是异步的。
您仍然可以使用cudaDeviceSynchronize进行真实尝试,但不要忘记在设备上设置the corresponding flag。