我正在使用CUDA实现某种图像处理算法,对于线程同步问题有一些疑问。
问题可以这样解释:
我们有一个大小为W * H的图像。 对于图像的每个像素,我需要运行9个相同数据的并行处理,并且每个进程都会产生一个值数组作为结果(整个算法中数组的长度相同,假设为N,大约为20或30)。对于每个像素,这9个进程将在完成计算后将它们的结果累积到最终数组中(每个像素只有一个单独的数组)。
为了并行化这个过程,我设计了以下结构:我生成尺寸为(10,10,9)的块,这意味着每个线程块将处理一个10×10大小的子图像,每个线程将处理一个单独像素的9个相同进程之一。 在这种情况下,网格尺寸将是(W / 10,H / 10,1)。 对于线程块,我将分配一个共享内存数组,其长度为100 * N,并且每个线程将根据其当前像素的坐标写入适当的共享内存位置。 因此,在这里我需要使用atomicAdd和__synchthreads()进行同步。
问题在于,如果像素的值为零,则我们根本不需要对其进行处理,因此我希望退出对于这样的像素,否则我会做无用功,因为图像的大部分都是零(背景)。 因此,我想写出以下内容:
//X and Y are the coordinates of the current pixel in the input image.
//threadIdx.z gives the index of the process among the 9 for the current pixel.
int X=blockIdx.x * blockDim.x + threadIdx.x;
int Y=blockIdx.y * blockDim.y + threadIdx.y;
int numOfProcessForTheCurrPixel=threadIdx.z;
int linearIndexOfPixelInBlock=threadIdx.y * blockDim.x + threadIdx.x;
unsigned short pixelValue=tex2D(image,X,Y);
//Here, threads processing zero-pixels will exit immediately.
if(pixelValue==0)
return;
float resultArray[22];
//Fill the result array according to our algorithm, mostly irrelevant stuff.
ProcessPixel(resultArray,X,Y,numOfProcessForTheCurrPixel);
for(int i=0;i<22;i++)
atomicAdd(&__sharedMemoryArray[22*linearIndexOfPixelInBlock + i],resultArray[i]);
__syncthreads();
//Then copy from the shared to the global memory and etc.
在这种情况下,让我担心的是编程指南所说的内容:
__syncthreads() 可以在条件代码中使用,但前提是整个线程块的条件计算结果必须完全相同,否则代码执行可能会挂起或产生意外的副作用。
因此,在我的情况下,如果一个10*10的线程块中的一些像素为零而另一些不为零,则属于零像素的线程将在开始时立即退出,而其他线程将继续处理。在这种情况下,同步是否仍然正常工作,还是会像编程指南所说的那样生成未定义的行为?我考虑让零像素线程处理垃圾数据以保持它们忙碌,但如果我们有完全由零组成的块(我们经常遇到这种情况),这将不必要地增加处理时间。在这种情况下应该怎么办?
__syncthread
,因此这段代码确实会导致死锁,正如talonmie所说。但是,如果您可以保证这一点(例如使用线程索引),那么您可以提前退出。请参见同一问题的我的新答案。 - chappjc