gpt4 book ai didi

c++ - 带有 clSetKernelArg 的 OpenCL 竞争条件

转载 作者:行者123 更新时间:2023-12-04 09:16:02 26 4
gpt4 key购买 nike

来自 Khronos 网站关于 clSetKernelArg 的线程安全:

All OpenCL API calls are thread-safe except clSetKernelArg, which is safe to call from any host thread, and is safe to call re-entrantly so long as concurrent calls operate on different cl_kernel objects. However, the behavior of the cl_kernel object is undefined if clSetKernelArg is called from multiple host threads on the same cl_kernel object at the same time.

我的问题是,是否有一种方法可以定义这种行为,使内核可以从多个线程读取和写入单个内核对象?

我认为被内核修改的对象上的 std::atomic 会阻止这种未定义的行为,但根据我的尝试,它会导致内核的输出产生错误的值。有没有更好的方法来实现这个/处理案例的已知技术?

在分配对象的大小如此之大以至于为每个内核执行重新创建一个新对象会消耗太多内存的情况下,它可能很有用,并且共享/可覆盖对象将是首选。

最佳答案

where kernels can read and write from a single kernel object from multiple threads?

“内核”是指在 GPU 上执行的代码片段,而“单个内核对象”是指主机代码中的cl_kernel? GPU 上的内核永远看不到主机端存在的 cl_kernel 结构。我假设您是在谈论内核使用缓冲区对象 (cl_mem) 参数。

您可以将cl_kernel 视为:

struct {
size_t num_args;
void* args[];
} _cl_kernel;
typedef struct _cl_kernel * cl_kernel;

如果您调用 clSetKernelArg(),它只是在该结构中设置一些内容。如果您调用 clEnqueueNDRangeKernel(),它会拍摄 cl_kernel 结构(参数)的快照,并将其附加到某个内部设备队列。我所说的“快照”并不是说它创建了实际 cl_mem 缓冲区内容的隐藏快照;它只是复制对 cl_mem 参数的引用。因为它是一个引用,所以无论您是使用来自多个线程的单个 cl_kernel 对象,还是您使用相同的名称多次调用 clCreateKernel,然后使用那些cl_kernel 在每个线程中;这只是一个方便的问题,最终结果是一样的。

如果您有一个有序的命令队列,您的内核将按入队顺序确定性地执行。如果您有多个命令队列(有序或乱序,无关紧要),则没有任何隐式顺序队列之间,因此如果您将相同的内核放入所有队列中,它们将以随机顺序执行。您可以使用事件强制执行显式 订单。 IOW,你这样做:

cl_event event1, event2;
cl_kernel K;
...
clEnqueueNDRangeKernel(queue_1, K, ... , &event1);
clEnqueueNDRangeKernel(queue_2, K, ... , 1, &event1, &event2);

等这将强制内核执行等待前一个,即使它们在不同的队列中。但是一次只有一个内核使用缓冲区。

如果您希望多个正在运行的内核同时使用同一个缓冲区,则取决于该缓冲区的使用模式。如果您只进行读取,则可以同时安全地使用来自任意数量内核的缓冲区。对于写入用途,如果您知道您只会写入缓冲区的一部分,则可以尝试使用子缓冲区 (clCreateSubBuffer)。否则你可能就不走运了(也许你可以尝试原子操作,但它可能会使算法慢得无法使用)。

关于c++ - 带有 clSetKernelArg 的 OpenCL 竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63212484/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com