C ++ amp原子

时间:2014-06-20 11:12:42

标签: c++ atomic c++-amp

我正在用C ++ AMP重写一个算法,然后遇到了原子写入的问题,更具体地说是atomic_fetch_add,这显然只适用于整数?

我需要以原子方式添加double_4(或者我必须使用float_4)。如何使用C ++ AMP的原子实现这一目标?

最好/唯一的解决方案是否真的有一个锁定变量,我的代码可以使用它来控制写入?我实际上需要为一长串输出双精度进行原子写操作,因此我基本上需要为每个输出都锁定。

我已经考虑过这个以获得更好的性能,但是现在我只是在第一次迭代中。

编辑: 感谢您已经给出的快速答案。 我虽然快速更新了我的问题。

我进行了以下锁定尝试,但似乎当warp中的一个线程通过锁定时,同一warp中的所有其他线程只是标记着。我期待第一个经线获得锁定,但我必须遗漏一些东西(请注意,自从我的cuda时代已经过去了几年,所以我刚刚变得愚蠢)

parallel_for_each(attracting.extent, [=](index<1> idx) restrict(amp)
{
   .....
   for (int j = 0; j < attracted.extent.size(); j++)
   {
      ...
      int lock = 0; //the expected lock value
      while (!atomic_compare_exchange(&locks[j], &lock, 1));
      //when one warp thread gets the lock, ALL threads continue on
      ...
      acceleration[j] += ...; //locked write
      locks[j] = 0; //leaving the lock again
   }
});

这不是一个大问题,因为我应该首先写入一个共享变量,并且只在一个tile中的所有线程完成后才将它写入全局内存,但我只是不明白这种行为。

3 个答案:

答案 0 :(得分:2)

所有原子添加操作仅适用于整数类型。对于float_4(我假设这是4个浮点数),您可以使用128位CAS(比较和交换)操作执行您想要的操作而不需要锁定,但是对于double_4,您不需要256位CAS操作。你要做的是有一个循环,从内存中原子地读取float_4,以常规方式执行float add,然后使用CAS测试&amp;如果它是原始值,则交换该值(如果不是则循环,即某些其他线程改变了read和amp; write之间的值)。请注意,128位CAS仅适用于64位体系结构,并且您的数据需要正确对齐。

答案 1 :(得分:1)

如果关键代码很短,您可以使用原子操作创建自己的锁:

int lock = 1;

while(__sync_lock_test_and_set(&lock, 0) == 0) // trying to acquire lock
{
 //yield the thread or go to sleep
} 

//critical section, do the work

// release lock
lock = 1;

优点是可以节省操作系统锁的开销。

答案 2 :(得分:0)

这个问题已被其他人回答,答案是你需要自己处理双原子。库中没有它的功能。

我还想详细说明我自己的编辑,以防其他人来到这里同样失败的锁定。

在下面的示例中,我的错误是没有意识到当交换失败时,它实际上改变了预期值!因此,第一个线程会期望锁定为零并在其中写入1。下一个线程会期望0并且将无法写入一个 - 但是然后交换机在变量中写入一个持有期望值的一个。这意味着下次线程尝试进行交换时,它需要锁定1!它得到它然后它认为它得到了锁。

我完全不知道&amp; lock在失败的交换比赛中会收到1!

parallel_for_each(attracting.extent, [=](index<1> idx) restrict(amp)
{
   .....
   for (int j = 0; j < attracted.extent.size(); j++)
   {
      ...
      int lock = 0; //the expected lock value

      **//note that, if locks[j]!=lock then lock=1
      //meaning that ACE will be true the next time if locks[j]==1
      //meaning the while will terminate even though someone else has the lock**
      while (!atomic_compare_exchange(&locks[j], &lock, 1));
      //when one warp thread gets the lock, ALL threads continue on
      ...
      acceleration[j] += ...; //locked write
      locks[j] = 0; //leaving the lock again
   }
});

似乎需要修复

parallel_for_each(attracting.extent, [=](index<1> idx) restrict(amp)
{
   .....
   for (int j = 0; j < attracted.extent.size(); j++)
   {
      ...
      int lock = 0; //the expected lock value

      while (!atomic_compare_exchange(&locks[j], &lock, 1))
      {
          lock=0; //reset the expected value
      };
      //when one warp thread gets the lock, ALL threads continue on
      ...
      acceleration[j] += ...; //locked write
      locks[j] = 0; //leaving the lock again
   }
});