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