我怎么能避免这个OpenMP关键部分的原始指针?

时间:2014-09-17 13:01:03

标签: c++ c++11 reference openmp

我有std::deque<std::reference_wrapper<MyType>> mydeque。我需要一个返回前值的函数(作为普通引用)并从队列中弹出它。由于std::deque不是线程安全的,因此应该保护访问权限(我正在使用OpenMP)。

我想出了下面的丑陋代码。拥有这样的高级结构然后回到原始指针看起来非常糟糕。

MyType & retrieve() {
  MyType* b;
  #pragma omp critical(access_mydeque)
  {
    b = &(mydeque.front().get());
    mydeque.pop_front();
  }
  return *b;
}

问题是我无法在的关键部分内返回,但我也无法在关键部分之前声明引用(_wrapper)(因为它必须分配给某事)...有办法解决这个问题吗?

2 个答案:

答案 0 :(得分:2)

我能想到的任何解决方案都涉及使用omp_lock_t代替critical构造和管理omp_lock_t所有权的RAII类:

class LockGuard {
public:  
    explicit LockGuard(omp_lock_t& lock) : m_lock(lock){
        omp_set_lock(&m_lock);
    }

    ~LockGuard() {
        omp_unset_lock(&m_lock);
    }

private:
  omp_lock_t& m_lock;
};

然后你可以将你已经拥有的代码修改为:

MyType & retrieve() {
    LockGuard guard(mydeque_lock);
    auto b = mydeque.front();
    mydeque.pop_front();
    return b;
}

或更好,编写自己的线程安全容器来聚合锁和std::deque

template<class T>
class MtLifo {
public:
    MtLifo() {
       omp_init_lock(&m_lock);
    }

    typename std::deque<T>::reference front_and_pop() {
        LockGuard guard(m_lock);
        auto b = m_stack.front();
        m_stack.pop_front();
        return b;
    }

    void push_front(const T& value) {
        LockGuard guard(m_lock);
        m_stack.push_front(value);
    }


    ~MtLifo() {
        omp_destroy_lock(&m_lock);
    }

private:
   std::deque<T> m_stack;
   omp_lock_t m_lock;
}

答案 1 :(得分:1)

你可以简单地使用TBB的并行数据结构https://software.intel.com/en-us/node/506076(虽然因为没有concurrent_deque它们可能不适合你:-()。

它们不要求您也使用TBB来描述代码的并行性方面,因此可以混合到OpenMP代码中。 (当然,既然你正在使用C ++,你可能会发现TBB的可扩展,可组合,并行的方法比OpenMP更友好,但这是一个可分离的决定。)