【问题标题】:atomicInc() is not workingatomicInc() 不工作
【发布时间】:2013-08-03 06:09:40
【问题描述】:

我已经使用 atomicInc() 尝试了下面的程序。

__global__ void ker(int *count)
{
    int n=1;
    int x = atomicInc ((unsigned int *)&count[0],n);
    CUPRINTF("In kernel count is %d\n",count[0]);
}

int main()
{
    int hitCount[1];
    int *hitCount_d;

    hitCount[0]=1;
    cudaMalloc((void **)&hitCount_d,1*sizeof(int));

    cudaMemcpy(&hitCount_d[0],&hitCount[0],1*sizeof(int),cudaMemcpyHostToDevice);

    ker<<<1,4>>>(hitCount_d);

    cudaMemcpy(&hitCount[0],&hitCount_d[0],1*sizeof(int),cudaMemcpyDeviceToHost);

    printf("count is %d\n",hitCount[0]);
  return 0;
}

输出是:

In kernel count is 1
In kernel count is 1
In kernel count is 1
In kernel count is 1

count is 1

我不明白为什么它没有增加。谁能帮忙

【问题讨论】:

  • 看起来你真的想使用 atomicAdd,而不是 atomicInc。
  • @talonmies 谢谢你。我已经使用 atomicAdd() 然后它正在工作。但我怀疑在哪种情况下我们可以使用 atomicInc().?

标签: cuda gpu-atomics


【解决方案1】:

参考documentationatomicInc 这样做:

以下:

atomicInc ((unsigned int *)&count[0],n);

计算:

((count[0] >= n) ? 0 : (count[0]+1))

并将结果存储回count[0]

(如果您不确定? 运算符的作用,请查看here

由于您已经传递了n = 1,并且count[0] 从 1 开始,atomicInc 实际上从未将变量 count[0] 增加超过 1。

如果您希望看到它的增量超过 1,请为 n 传递一个更大的值。

变量n 实际上充当递增过程的“翻转值”。当要递增的变量实际达到n的值时,下一个atomicInc会将其重置为零。

虽然您没有问过这个问题,但您可能会问:“如果我达到了翻转值,为什么我永远看不到零值?”

要回答这个问题,您必须记住所有 4 个线程都在同步执行。它们都执行atomicInc指令,然后再执行后续的打印语句。

因此,我们有一个变量 count[0],它从 1 开始。

  1. 执行原子的第一个线程将其重置为零。
  2. 下一个线程将其增加到 1。
  3. 第三个线程将其重置为零。
  4. 第四个也是最后一个线程将其增加到 1。

然后所有 4 个线程都打印出该值。

作为另一个实验,尝试启动 5 个线程而不是 4 个,看看您是否可以预测打印输出的值。

ker<<<1,5>>>(hitCount_d);

如 cmets 中的 @talonmies 所示,如果您将 atomicInc 换成 atomicAdd

int x = atomicAdd ((unsigned int *)&count[0],n);

你会得到你可能期望的结果。

【讨论】:

  • atomicInc(ptrToInt, INT_MAX)atomicAdd(ptrToInt, 1) 之间有性能差异吗?
  • 我不知道不同类型的原子指令之间的任何性能差异,也不知道任何描述原子吞吐量的正式文档。如果这是一个问题,应该可以编写一个相当简单的测试用例。除非您需要翻转功能,否则我不清楚为什么要使用atomicInc。如果您确实需要它,atomicAdd 不是一个普遍可行的替代品。
猜你喜欢
  • 1970-01-01
  • 2021-01-10
  • 1970-01-01
  • 2019-01-19
  • 1970-01-01
  • 2018-12-22
  • 2016-04-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多