这是我用于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
谢谢!
答案 0 :(得分:1)
我在声明中没有看到任何问题。如果由于某些原因你不确定GCC原子,请使用我确定的TBB原子。
但我发现问题是使用mutable
关键字来访问const
仿函数中的字段。 mutable
通常是糟糕设计的标志。在并行编程中,它的使用特别容易出错。如果并行调用的方法标记为const,则通常意味着它将在仿函数类的同一实例上并行调用。因此,您在可变字段上进行了数据竞争。
您可以将local_value移动到operator()
的范围内,或者尝试使用线程局部容器tbb::combinable
或tbb::enumerable_thread_specific
来缓存特定于线程的部分值,而不是破坏const限制,或者应用并行缩减算法tbb::parallel_reduce
,您可以安全地将部分结果存储在仿函数的主体中。