解决方案:
最后,我可以解决或者至少为我的问题找到一个好的解决方法。 这种信号量在NVIDIA的情况下不起作用。 我认为this评论是对的。
所以我决定使用 atomic_add(),这是OpenCL 1.1的必备部分。 我有一个 resultBuffer 数组和 resultBufferSize 全局变量,最后一个设置为零。
当我有结果(我的结果总是!! x数字)比我简单的调用 position = atomic_add(resultBufferSize,x); 我可以肯定没有人在位置和位置+ x之间写入缓冲区。
不要忘记全局变量必须是易变的。
当线程遇到无限循环时,资源不可用,因此缓冲区读取期间的-5错误代码。
更新
当我回读时:
oclErr |= clEnqueueReadBuffer(cqCommandQueue, cm_inputNodesArraySizes, CL_TRUE, 0, lastMapCounter*sizeof(cl_uint), (void*)&inputNodesArraySizes, 0, NULL, NULL);
lastMapCounter的值发生了变化。这很奇怪,因为在ocl代码中我什么都不做,我会处理大小:我写入缓冲区创建的内容以及我复制的内容我读回来的内容相同。而隐藏的缓冲区溢出确实会导致许多困扰。
更新结束
我做了以下代码,其中有一个错误。我想要一个信号量来改变resultBufferSize全局变量(现在我只是想尝试它是如何工作的)并获得一个大数字(假设每个工作者写一些东西)。但我总是得到3或有时错误。编译器的工作原理没有逻辑。
__kernel void findCircles(__global uint *inputNodesArray, __global
uint*inputNodesArraySizes, uint lastMapCounter,
__global uint *resultBuffer,
__global uint *resultBufferSize, volatile __global uint *sem)
{
for(;atom_xchg(sem, 1) > 0;)
(*resultBufferSize) = (*resultBufferSize) + 3;
atom_xchg(sem, 0);
}
我在内核执行期间得到-48,有时它没关系,当我想读回缓冲区(大小缓冲区)时,我得到-5。
你知道我在哪里可以找到这个bug吗?
使用NVIDIA opencl 1.1。
当然在主机上我配置得很好:
uint32 resultBufferSize = 0;
uint32 sem;
cl_mem cmresultBufferSize = clCreateBuffer(cxGPUContext, CL_MEM_READ_WRITE,
sizeof(uint32), NULL, &ciErrNum);
cl_mem cmsem = clCreateBuffer(cxGPUContext, CL_MEM_READ_WRITE, sizeof(uint32), NULL,
&ciErrNum);
ciErrNum = clSetKernelArg(ckKernel, 4, sizeof(cl_mem), (void*)&cmresultBufferSize);
ciErrNum = clSetKernelArg(ckKernel, 5, sizeof(cl_mem), (void*)&cmsem);
ciErrNum |= clEnqueueNDRangeKernel(cqCommandQueue, ckKernel, 1, NULL,
&szGlobalWorkSize, &szLocalWorkSize, 0, NULL, NULL);
ciErrNum = clEnqueueReadBuffer(cqCommandQueue, cmresultBufferSize, CL_TRUE, 0,
sizeof(uint32), (void*)&resultBufferSize, 0, NULL, NULL);
(如果是这段代码,则内核正常,最后一次读取为-5)
答案 0 :(得分:0)
我知道你已经就此得出结论,但我想指出两件事: 1)信号量是不可移植的,因为它不是SIMD安全的,正如链接线程中所指出的那样。 2)内存模型不够强大,无法赋予代码含义。结果缓冲区的更新可能会移出临界区 - 否则模型中没有任何内容。至少你需要围栏,但1.x规格中围栏的语言也相当薄弱。您需要一个OpenCL 2.0实现才能确信这方面是安全的。