代码之家  ›  专栏  ›  技术社区  ›  Konrad Rudolph

使用OpenMP原子操作获取和添加

  •  8
  • Konrad Rudolph  · 技术社区  · 14 年前

    相反,我正在寻找一种利用OpenMPs原子操作来实现这一点的方法,但我遇到了一个死胡同。你能做到吗?N、 B.以下代码 几乎

    #pragma omp atomic
    x += a
    

    几乎但不完全,因为我真的需要 x . fetch_and_add

    template <typename T>
    T fetch_and_add(volatile T& value, T increment) {
        T old;
        #pragma omp critical
        {
            old = value;
            value += increment;
        }
        return old;
    }
    

    (如果我没有弄错的话,可以问一个等价的问题来比较和交换,但是一个可以用另一个来实现。)

    2 回复  |  直到 14 年前
        1
  •  4
  •   Jason    13 年前

    从openmp 3.1开始,支持捕获原子更新,您可以捕获旧值或新值。因为我们必须从内存中引入值来增加它,所以我们应该能够从一个CPU寄存器访问它并将它放入一个线程私有变量中。

    如果使用gcc(或g++),可以找到原子内置: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html

    它认为英特尔的C/C++编译器也支持这一点,但我没有尝试过。

    template <class T>
    inline T my_fetch_add(T *ptr, T val) {
      #ifdef GCC_EXTENSION
      return __sync_fetch_and_add(ptr, val);
      #endif
      #ifdef OPENMP_3_1
      T t;
      #pragma omp atomic capture
      { t = *ptr; *ptr += val; }
      return t;
      #endif
    }
    

    更新:我刚试用了英特尔的C++编译器,它目前支持OpenMP 3.1(实现原子捕获)。英特尔提供在linux中免费使用编译器的非商业用途:

    http://software.intel.com/en-us/articles/non-commercial-software-download/

    GCC4.7将支持OpenMP3.1,当它最终发布时。。。希望很快:)

        2
  •  2
  •   osgx    14 年前

    fetch_and_add(int *x, int a) {
     #pragma omp atomic
     *x += a;
    
     return (*x-a);
    }
    

    更新:这不是一个真正的答案,因为x可以被另一个线程在原子之后修改。 因此,似乎不可能使用OMP Pragmas实现通用的“Fetch and add”。作为通用的,我指的是操作,它可以很容易地从OMP代码的任何地方使用。

    你可以用 omp_*_lock 模拟原子的函数:

    typedef struct{omp_lock_t lock;int value;}模拟原子结构;

    fetch_and_add(atomic_simulated_t *x, int a)
    {
      int ret;
      omp_set_lock(x->lock);
      x->value +=a;
      ret = x->value;
      omp_unset_lock(x->lock);
    }
    

    这是丑陋和缓慢的(做一个2原子操作而不是1)。但是如果你希望你的代码是非常可移植的,那么它并不是所有情况下最快的。

    你说“如下(仅限非锁定)”。但“非锁定”操作(使用CPU的“LOCK”前缀,或LL/SC等)和锁定操作(使用多个原子指令自行实现,忙循环用于短时间等待解锁,操作系统睡眠用于长时间等待)之间有什么区别?