Cuda原子锁:按顺序排列的线程

Cuda原子锁:按顺序排列的线程,cuda,gpu-atomics,Cuda,Gpu Atomics,我有一个代码,其中一个部分需要严格执行。我对这段代码使用了一个锁,这样内核的每个线程(设置为每个块一个线程)都可以原子地执行这段代码。线程的顺序是困扰我的-我需要线程按照时间顺序执行,根据它们的索引(或者实际上,按照它们的blockIdx的顺序),从0到10(而不是随机执行,例如5、8、3、0等等)。有可能吗 下面是一个示例代码: #include<stdio.h> #include<stdlib.h> #include<math.h> #include<

我有一个代码,其中一个部分需要严格执行。我对这段代码使用了一个锁,这样内核的每个线程(设置为每个块一个线程)都可以原子地执行这段代码。线程的顺序是困扰我的-我需要线程按照时间顺序执行,根据它们的索引(或者实际上,按照它们的blockIdx的顺序),从0到10(而不是随机执行,例如5、8、3、0等等)。有可能吗

下面是一个示例代码:

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<math_functions.h>
#include<time.h>
#include<cuda.h>
#include<cuda_runtime.h>

// number of blocks
#define nob 10

struct Lock{
  int *mutex;
  Lock(void){
    int state = 0;
    cudaMalloc((void**) &mutex, sizeof(int));
    cudaMemcpy(mutex, &state, sizeof(int), cudaMemcpyHostToDevice);
  }
  ~Lock(void){
    cudaFree(mutex);
  }
  __device__ void lock(void){
    while(atomicCAS(mutex, 0, 1) != 0);
  }
  __device__ void unlock(void){
    atomicExch(mutex, 0);
  }
};


__global__ void theKernel(Lock myLock){
  int index = blockIdx.x; //using only one thread per block

  // execute some parallel code

  // critical section of code (thread with index=0 needs to start, followed by index=1, etc.)
  myLock.lock();

  printf("Thread with index=%i inside critical section now...\n", index);

  myLock.unlock();
}

int main(void)
{
  Lock myLock;
  theKernel<<<nob, 1>>>(myLock);
  return 0;
}
我希望这些索引从0开始,按时间顺序执行到9

我认为修改锁以实现此目的的一种方法如下:

struct Lock{
  int *indexAllow;
  Lock(void){
    int startVal = 0;
    cudaMalloc((void**) &indexAllow, sizeof(int));
    cudaMemcpy(indexAllow, &startVal, sizeof(int), cudaMemcpyHostToDevice);
  }
  ~Lock(void){
    cudaFree(indexAllow);
  }
  __device__ void lock(int index){
    while(index!=*indexAllow);
  }
  __device__ void unlock(void){
    atomicAdd(indexAllow,1);
  }
};
然后通过将索引作为参数传递来初始化锁:

myLock.lock(index);
但这会使我的电脑停滞。。。我可能错过了一些明显的东西

如果有人能帮忙,我将不胜感激


谢谢

我把你的代码改了一点。现在,它将生成所需的输出:

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<math_functions.h>
#include<time.h>
#include<cuda.h>
#include<cuda_runtime.h>

// number of blocks
#define nob 10

struct Lock{
  int *mutex;
  Lock(void){
    int state = 0;
    cudaMalloc((void**) &mutex, sizeof(int));
    cudaMemcpy(mutex, &state, sizeof(int), cudaMemcpyHostToDevice);
  }
  ~Lock(void){
    cudaFree(mutex);
  }
  __device__ void lock(uint compare){
    while(atomicCAS(mutex, compare, 0xFFFFFFFF) != compare);    //0xFFFFFFFF is just a very large number. The point is no block index can be this big (currently).
  }
  __device__ void unlock(uint val){
    atomicExch(mutex, val+1);
  }
};


__global__ void theKernel(Lock myLock){
  int index = blockIdx.x; //using only one thread per block

  // execute some parallel code

  // critical section of code (thread with index=0 needs to start, followed by index=1, etc.)
  myLock.lock(index);
  printf("Thread with index=%i inside critical section now...\n", index);
  __threadfence_system();   // For the printf. I'm not sure __threadfence_system() can guarantee the order for calls to printf().
  myLock.unlock(index);
}

int main(void)
{
  Lock myLock;
  theKernel<<<nob, 1>>>(myLock);
  return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
//街区数
#定义nob 10
结构锁{
int*互斥;
锁(空){
int state=0;
cudamaloc((void**)和互斥,sizeof(int));
cudaMemcpy(互斥、状态、sizeof(int)、cudamemcpyhostodevice);
}
~Lock(无效){
cudaFree(互斥);
}
__设备无效锁(uint比较){
while(atomicCAS(mutex,compare,0xFFFFFFFF)!=compare);//0xFFFFFFFF只是一个非常大的数字。关键是没有块索引可以这么大(当前)。
}
__设备无效解锁(uint val){
原子exch(互斥,val+1);
}
};
__全局_uu;使内核无效(锁定myLock){
int index=blockIdx.x;//每个块只使用一个线程
//执行一些并行代码
//代码的关键部分(需要启动索引为0的线程,然后是索引为1的线程,等等)
myLock.lock(索引);
printf(“索引为%i的线程现在位于临界段内…\n”,索引);
__threadfence_system();//用于printf。我不确定uu threadfence_system()能否保证调用printf()的顺序。
myLock.unlock(索引);
}
内部主(空)
{
锁定myLock;
内核(myLock);
返回0;
}
lock()
函数接受
compare
作为参数,并检查它是否等于
mutex
中的值alraedy。如果是,它将
0xFFFFFFFF
放入
互斥锁
,以指示锁是由线程获取的。由于
互斥体在构造函数中由0初始化,因此只有块ID为0的线程才能成功获取锁。在
解锁
中,我们将下一个块ID索引放入
互斥锁
,以保证您所需的顺序。另外,由于您在CUDA内核中使用了
printf()
,我认为需要调用
threadfence\u system()
,才能在输出中以相同的顺序查看它们。

请参阅。有时,我可以通过在CPU上运行上述部分来解决这个问题(来回复制很慢,但尽管我们所有cuda程序员都希望如此,但CPU在某些操作中要快得多)。其他解决方案取决于关键部分发生的情况。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<math_functions.h>
#include<time.h>
#include<cuda.h>
#include<cuda_runtime.h>

// number of blocks
#define nob 10

struct Lock{
  int *mutex;
  Lock(void){
    int state = 0;
    cudaMalloc((void**) &mutex, sizeof(int));
    cudaMemcpy(mutex, &state, sizeof(int), cudaMemcpyHostToDevice);
  }
  ~Lock(void){
    cudaFree(mutex);
  }
  __device__ void lock(uint compare){
    while(atomicCAS(mutex, compare, 0xFFFFFFFF) != compare);    //0xFFFFFFFF is just a very large number. The point is no block index can be this big (currently).
  }
  __device__ void unlock(uint val){
    atomicExch(mutex, val+1);
  }
};


__global__ void theKernel(Lock myLock){
  int index = blockIdx.x; //using only one thread per block

  // execute some parallel code

  // critical section of code (thread with index=0 needs to start, followed by index=1, etc.)
  myLock.lock(index);
  printf("Thread with index=%i inside critical section now...\n", index);
  __threadfence_system();   // For the printf. I'm not sure __threadfence_system() can guarantee the order for calls to printf().
  myLock.unlock(index);
}

int main(void)
{
  Lock myLock;
  theKernel<<<nob, 1>>>(myLock);
  return 0;
}