使用TBB parallel_for_each()减少到原子计数器

时间:2014-05-06 05:49:26

标签: c++ multithreading c++11 tbb reduction

这是我用于TBB代码的原子计数器类。

#include <atomic>
template <typename T = int>
struct AtomicCounter {

private:
std::atomic<T> value;
std::atomic<T> num_inter;

public:
void put_inter(T niter) {
T x = num_inter.fetch_add(niter);
}

T get_inter() { return num_inter.load(); }

void increment() {  ++value; }
void put(T data) {  value.fetch_add(data) ; // ignore the old value returned }
void decrement() {  --value; }
T    get()       { return value.load(); }

};

我正在使用并行foreach循环,其中每个线程都有自己的本地计数器值,并使用AtomicCounter类的put函数更新全局计数器对象。并行foreach的函数对象将此全局计数器作为引用。

template<typename counter_t>
struct my_functor {
 public:
  my_functor(){}
  my_functor(counter_t &c):m_c(c){ } 

  template<typename label_t>
  void operator()(label_t label) const {

  // do some work --> local counter

   m_c.put(local_value); // put the local counter value in the global counter 
  } 

  private:
    counter_t& m_c;
    mutable int local_value; //local counter value  

  }

   // for TBB 
 //declare an object of this class as a global counter.

 AtmoicCounter<int> c;
 my_functor<atomicCounter<int>>  func(c) //functor object
 parallel_for_each( mywork.begin(), mywork.end(), func)    //TBB parallel for each
基本上,每个线程都会更新全局计数器。在我声明std :: atomic成员的atomicCounter类中有什么问题吗?我正在使用GCC 4.7.2与C ++ 11功能和英特尔TBB 4.2

谢谢!

1 个答案:

答案 0 :(得分:1)

我在声明中没有看到任何问题。如果由于某些原因你不确定GCC原子,请使用我确定的TBB原子。

但我发现问题是使用mutable关键字来访问const仿函数中的字段。 mutable通常是糟糕设计的标志。在并行编程中,它的使用特别容易出错。如果并行调用的方法标记为const,则通常意味着它将在仿函数类的同一实例上并行调用。因此,您在可变字段上进行了数据竞争。

您可以将local_value移动到operator()的范围内,或者尝试使用线程局部容器tbb::combinabletbb::enumerable_thread_specific来缓存特定于线程的部分值,而不是破坏const限制,或者应用并行缩减算法tbb::parallel_reduce,您可以安全地将部分结果存储在仿函数的主体中。