OpenCL内核执行未完成时能否重新设置参数并再次入队?
OpenCL内核多次执行参数修改问题解答
绝对不能在第一次内核执行请求未完成(对应event未结束)时,调用clSetKernelArg修改同一个cl_kernel对象的参数,这种操作会引发不可预测的问题。
原因说明
虽然Khronos文档没有直接明确禁止该操作,但从OpenCL的对象模型和实现逻辑来看:
cl_kernel对象的参数属于其内部状态,部分OpenCL实现不会在调用clEnqueueNDRangeKernel时立即捕获参数快照,而是延迟到内核实际开始执行时才读取参数值。如果在第一次执行完成前修改参数,会导致第一次执行读取到错误的参数,引发计算结果错误、设备异常等问题。cl_kernel对象并非线程安全,并发修改其参数与提交执行请求会触发竞态条件,属于OpenCL规范中的未定义行为。
正确实现方案
有两种可靠的方式实现同一内核两次带不同参数的执行:
方案1:等待第一次执行完成后再修改参数
先通过clWaitForEvents等待第一次内核执行结束,再更新参数并提交第二次请求:
cl_kernel kernel = clCreateKernel(program, "target_kernel", &err); // 第一次执行 clSetKernelArg(kernel, 0, sizeof(cl_mem), &buffer1); cl_event event; clEnqueueNDRangeKernel(cmd_queue, kernel, 1, NULL, &global_size, &local_size, 0, NULL, &event); // 等待第一次执行完成 clWaitForEvents(1, &event); clReleaseEvent(event); // 更新参数并提交第二次执行 clSetKernelArg(kernel, 0, sizeof(cl_mem), &buffer2); clEnqueueNDRangeKernel(cmd_queue, kernel, 1, NULL, &global_size, &local_size, 0, NULL, NULL); // 后续清理 clReleaseKernel(kernel);
方案2:创建多个独立的内核对象
从同一个cl_program创建多个cl_kernel实例,分别设置不同参数后可独立提交执行,无需等待:
cl_kernel kernel1 = clCreateKernel(program, "target_kernel", &err); cl_kernel kernel2 = clCreateKernel(program, "target_kernel", &err); // 分别设置不同参数 clSetKernelArg(kernel1, 0, sizeof(cl_mem), &buffer1); clSetKernelArg(kernel2, 0, sizeof(cl_mem), &buffer2); // 可同时提交两次执行请求 clEnqueueNDRangeKernel(cmd_queue, kernel1, 1, NULL, &global_size, &local_size, 0, NULL, NULL); clEnqueueNDRangeKernel(cmd_queue, kernel2, 1, NULL, &global_size, &local_size, 0, NULL, NULL); // 后续清理 clReleaseKernel(kernel1); clReleaseKernel(kernel2);
内容的提问来源于stack exchange,提问作者Evgeny Aleksandrov
相关产品推荐
相关产品推荐

