Использование TBB parallel_for_each () с сокращением до атомных счетчиков

Вот мой класс атомного счетчика, используемый для кода 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, в котором каждый поток имеет свое собственное значение локального счетчика, и он обновляет объект глобального счетчика, используя функцию put класса AtomicCounter. Объект функции для параллельного 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

В общем, каждый поток обновляет глобальный счетчик. Что-то не так с классом atomicCounter, где я объявляю член std :: atomic? Я использую GCC 4.7.2 с функциями C ++ 11 и Intel TBB 4.2

Спасибо!

0

Решение

Я не вижу никаких проблем в декларациях. Если вы по какой-то причине не уверены в атомарности GCC, используйте атомарность TBB, в которой я уверен.

Но где я вижу, проблема заключается в использовании mutable ключевое слово для доступа к полям из const функтор. mutable часто является признаком плохого дизайна. И в параллельном программировании его использование особенно подвержено ошибкам. Если метод, который вызывается параллельно, помечается как const, это часто означает, что он будет вызван параллельно в том же экземпляре класса функтора. Таким образом, у вас есть гонка данных на изменчивом поле.

Вместо того, чтобы нарушать ограничения const, вы можете переместить local_value в область действия operator()или попробуйте локальные контейнеры tbb::combinable или же tbb::enumerable_thread_specific кэшировать частичные значения, специфичные для потока, или применять алгоритм параллельного сокращения tbb::parallel_reduce где вы можете безопасно хранить частичные результаты в теле функтора.

1

Другие решения


По вопросам рекламы [email protected]