我有一段串行代码可以做这样的事情
if( ! variable )
{
do some initialization here
variable = true;
}
据我所知,这在串行中完美无缺,只执行一次。什么原子操作在CUDA中是正确的?
答案 0 :(得分:7)
在我看来,你想要的是你代码中的“关键部分”。关键部分允许一个线程执行一系列指令,同时阻止任何其他线程或线程块执行这些指令。
例如,关键部分可用于控制对内存区域的访问,以允许单个线程对该区域进行无冲突访问。
Atomics本身只能用于单个变量的非常有限的,基本上单一的操作。但是原子可以用来建立一个关键部分。
您应该在内核中使用以下代码来控制对关键部分的线程访问:
__syncthreads();
if (threadIdx.x == 0)
acquire_semaphore(&sem);
__syncthreads();
//begin critical section
// ... your critical section code goes here
//end critical section
__syncthreads();
if (threadIdx.x == 0)
release_semaphore(&sem);
__syncthreads();
在内核之前定义这些辅助函数和设备变量:
__device__ volatile int sem = 0;
__device__ void acquire_semaphore(volatile int *lock){
while (atomicCAS((int *)lock, 0, 1) != 0);
}
__device__ void release_semaphore(volatile int *lock){
*lock = 0;
__threadfence();
}
我已成功测试并使用了上述代码。请注意,它基本上使用每个线程块中的线程0作为请求者在 threadblocks 之间进行仲裁。如果您只希望获胜线程块中的一个线程执行关键部分代码,则应进一步调整(例如if (threadIdx.x < ...)
)您的关键部分代码。
在信号量的warp仲裁中有多个线程会带来额外的复杂性,所以我不推荐这种方法。相反,如我在此处所示,让每个线程块进行仲裁,然后使用普通的线程块通信/同步方法(例如__syncthreads()
,共享内存等)控制您在获胜线程块中的行为。
请注意,此方法的性能代价很高。当您无法弄清楚如何并行化算法时,您应该只使用关键部分。
最后,一句警告。与任何线程并行体系结构一样,关键部分的不当使用可能导致死锁。特别是,对线程块内的线程块和/或warp的执行顺序做出假设是一种有缺陷的方法。