Cuda原子改变旗帜

Tha*_*ude 3 cuda atomic

我有一段串行代码,可以做这样的事情

if( ! variable )
{
  do some initialization here 
  variable = true;
}
Run Code Online (Sandbox Code Playgroud)

据我所知,这在串行中完美无缺,只执行一次.什么原子操作在CUDA中是正确的?

Rob*_*lla 7

在我看来,你想要的是你的代码中的"关键部分".关键部分允许一个线程执行一系列指令,同时防止任何其他线程或线程块执行这些指令.

例如,临界区可用于控制对存储区的访问,以允许单个线程对该区域的不冲突访问.

原子本身只能用于单个变量上非常有限的,基本上单一的操作.但是原子可以用来构建一个关键部分.

您应该在内核中使用以下代码来控制对关键部分的线程访问:

__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();
Run Code Online (Sandbox Code Playgroud)

在内核之前定义这些辅助函数和设备变量:

__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();
  }
Run Code Online (Sandbox Code Playgroud)

我已成功测试并使用了上述代码.注意,它基本上在每个线程块中使用线程0作为请求者的线程块之间进行仲裁.if (threadIdx.x < ...)如果您只希望获胜线程块中的一个线程执行关键部分代码,则应进一步调整(例如)您的关键部分代码.

在一个变换器的warp仲裁中有多个线程会带来额外的复杂性,所以我不推荐这种方法.相反,让每个线程块按照我在此处所示进行仲裁,然后使用普通线程块通信/同步方法(例如__syncthreads(),共享内存等)控制您在获胜线程块内的行为

请注意,此方法的性能代价很高.当您无法弄清楚如何以其他方式并行化算法时,您应该只使用关键部分.

最后,一句警告.与任何线程并行体系结构一样,关键部分的不当使用可能导致死锁.特别是,对线程块内的线程块和/或warp的执行顺序做出假设是一种有缺陷的方法.

  • 此处临界区协商背后的一个想法是您可能在线程块中使用多个线程来执行临界区“工作”。在这种情况下,在主线程正确协商并获取全局锁之前,它们不应开始“工作”。`__syncthreads()` 将强制执行该行为,并且它们还将强制所有线程在释放锁之前完成临界区“工作”。如果您不需要线程块中的那种协作行为,您可能不需要`__syncthreads()`。 (2认同)