CUDA C 代码不改变,只是在核函数中加了几个printf,输出结果就变了

  • 5 replies
  • 1187 views
核函数如下,这是一个交换数组中元素顺序的核函数,数组大概有一万多个元素。如果按下面的代码直接输出,结果是错的,但是如果我在
const int oldpos = sortpart[p];这句前加上printf来输出未改变顺序前的数组的值之后,下面输出结果只有一个是错的,其他都是对的,请问这是怎么回事啊


_global__ void KerSortBasicArrays(int a, int* sortpart, double3* totalCoorg, double3* totalCoor,int3*CCg,int3*cc)
{
   
   const int p = blockIdx.x*blockDim.x + threadIdx.x; //-Particle number
   if (p<a){
   
      const int oldpos = sortpart[p];
      totalCoor[p] = totalCoorg[oldpos];
      cc[p] = CCg[oldpos];

      Swap<double3>(totalCoorg[p], totalCoor[p]);
      Swap<int3>(CCg[p], cc[p]);
      if (p >= 3860 && p < 3870)
      printf("totalCoor[%d]的值为  %lf ,%lf ,%lf  \n", p, totalCoorg[p].x, totalCoorg[p].y, totalCoorg[p].z);   

   }
}

这个问题还是不知道怎么回事,不过暂时不影响下面的调试了 :'(

核函数如下,这是一个交换数组中元素顺序的核函数,数组大概有一万多个元素。如果按下面的代码直接输出,结果是错的,但是如果我在
const int oldpos = sortpart[p];这句前加上printf来输出未改变顺序前的数组的值之后,下面输出结果只有一个是错的,其他都是对的,请问这是怎么回事啊


_global__ void KerSortBasicArrays(int a, int* sortpart, double3* totalCoorg, double3* totalCoor,int3*CCg,int3*cc)
{
   
   const int p = blockIdx.x*blockDim.x + threadIdx.x; //-Particle number
   if (p<a){
   
      const int oldpos = sortpart[p];
      totalCoor[p] = totalCoorg[oldpos];
      cc[p] = CCg[oldpos];

      Swap<double3>(totalCoorg[p], totalCoor[p]);
      Swap<int3>(CCg[p], cc[p]);
      if (p >= 3860 && p < 3870)
      printf("totalCoor[%d]的值为  %lf ,%lf ,%lf  \n", p, totalCoorg[p].x, totalCoorg[p].y, totalCoorg[p].z);   

   }
}

如果只看帖子中的代码,则逻辑上是简单的。但是如果这样简单的代码都能导致Swap()没有执行成功的话,这里可能是怀疑的一点:
const int p = blockIdx.x*blockDim.x + threadIdx.x; //-Particle number
....
 
const int oldpos = sortpart[p];
totalCoor[p] = totalCoorg[oldpos];
cc[p] = CCg[oldpos];
...
Swap<double3>(totalCoorg[p], totalCoor[p]);
Swap<int3>(CCg[p], cc[p]);
...
我们用CCg[]举例,这里面你同时1个线程读写了CCg[p]和CCg[oldpos], 按照你的Swap()的写法,如果想多线程安全的,必须要能保证在不同的线程中:
(1)p的值是唯一的, 这个来自于你的线程索引,一般情况没问题。
(2)oldpos的值是唯一的,这个来源于sortpart[p], 可能会有问题(不一定,要看sortpart[]里面的元素分布本身)
(3)任何一个线程中的查表得到的oldpos, 不能恰好等于另外一个线程中的p,这个也不一定。

所以楼主不妨按照这里的三种情况排查一下,如果有任何一种情况,就会造成竞态,形成类似你加入一个printf之类的影响了线程间执行的时机的东西,就会让结果发生变化(哪怕它并不直接干涉你的数组们,只要它会占用执行时间,就会改变结果)。

您好,我按您说的检查了,但是发现您说的这三种情况都没有发生。我用cuda-memcheck检查了内存。总是显示是这个函数上面核函数非法访问内存的问题,请问上面的核函数出问题了,是否会造成这个函数中输出错误的这种情况呢?

您好,我按您说的检查了,但是发现您说的这三种情况都没有发生。我用cuda-memcheck检查了内存。总是显示是这个函数上面核函数非法访问内存的问题,请问上面的核函数出问题了,是否会造成这个函数中输出错误的这种情况呢?

你给的代码里面只有p和pos这几个坐标,用来访存。如今cuda-memcheck都报错了,还能说上面没问题(p或者pos再每个线程里面不重叠的对应数组里的具体位置?)

不妨先修正你的访存出错再说。然后再重新考虑上面三种情况(是否每个线程都拿到自己的有效位置)。

非常感谢您的回复,确实是导致了竞态,从而导致其他函数出现数组索引越界。