スレッド・ローカル・ストレージ用のテンプレート・クラス。
enum ets_key_usage_type {
ets__key_per_instance,
ets_no_key
};
template <typename T,
typename Allocator=cache_aligned_allocator<T>,
ets_key_usage_type ETS_key_type=ets_no_key>
class enumerable_thread_specific;
#include "tbb/enumerable_thread_specific.h"
enumerable_thread_specific は、T 型の要素にスレッド・ローカル・ストレージ (TLS) を提供します。 enumerable_thread_specific は、すべてのスレッドローカル要素のイテレーターと範囲を提供することにより、コンテナーとして動作します。
スレッドローカル要素は遅れて作成されます。新しく作成された enumerable_thread_specific には要素がありません。 スレッドが enumerable_thread_specific へのアクセスを要求すると、そのスレッドに対応する要素が作成されます。 要素の数は、アプリケーションで使用するスレッドの数ではなく、enumerable_thread_specific にアクセスする (個別の) スレッドの数と同じです。 enumerable_thread_specific を消去すると、要素がすべて削除されます。
ETS_key_usage_type パラメーターは、ネイティブの TLS キーを消費しない実装と、より高いパフォーマンスを提供するが enumerable_thread_specific のインスタンスごとに 1 つのネイティブな TLS キーを消費する特別な実装の選択に使用します。 ETS_key_usage_type パラメーターが提供されない場合、ets_no_key がデフォルトで使用されます。
注意:ネイティブ TLS の数は非常に小さな数 (例えば、64 または 128) に制限されます。 このため、最もパフォーマンス・クリティカルなケースにのみ ets_key_per_instance の特別な実装の使用を制限することを推奨します。
次のコードは、enumerable_thread_specific を使用する単純な例を示しています。 null_parallel_for_body::operator() の呼び出しの数および実行される反復数の合計は、parallel_for に参加する各スレッドによってカウントされます。これらのカウントはメインの最後で出力されます。
#include <cstdio>
#include <utility>
#include "tbb/task_scheduler_init.h"
#include "tbb/enumerable_thread_specific.h"
#include "tbb/parallel_for.h"
#include "tbb/blocked_range.h"
using namespace tbb;
typedef enumerable_thread_specific< std::pair<int,int> > CounterType;
CounterType MyCounters (std::make_pair(0,0));
struct Body {
void operator()(const tbb::blocked_range<int> &r) const {
CounterType::reference my_counter = MyCounters.local();
++my_counter.first;
for (int i = r.begin(); i != r.end(); ++i)
++my_counter.second;
}
};
int main() {
parallel_for( blocked_range<int>(0, 100000000), Body());
for (CounterType::const_iterator i = MyCounters.begin();
i != MyCounters.end(); ++i)
{
printf("Thread stats:\n");
printf(" calls to operator(): %d", i->first);
printf(" total # of iterations executed: %d\n\n",
i->second);
}
}
enumerable_thread_specific の combine(f) メソッドは、ラムダ式を使用して記述できるバイナリー・ファンクター f を使用してリダクションを行います。 例えば、前の例は、main 関数の最後に次の行を追加することにより、スレッドローカル値を合計するように拡張できます。
std::pair<int,int> sum =
MyCounters.combine([](std::pair<int,int> x,
std::pair<int,int> y) {
return std::make_pair(x.first+y.first,
x.second+y.second);
});
printf("Total calls to operator() = %d, "
"total iterations = %d\n", sum.first, sum.second);
namespace tbb {
template <typename T,
typename Allocator=cache_aligned_allocator<T>,
ets_key_usage_type ETS_key_type=ets_no_key >
class enumerable_thread_specific {
public:
// 基本型
typedef Allocator allocator_type;
typedef T value_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
typedef implementation-dependent size_type;
typedef implementation-dependent difference_type;
// イテレーター型
typedef implementation-dependent iterator;
typedef implementation-dependent const_iterator;
// 並列範囲型
typedef implementation-dependent range_type;
typedef implementation-dependent const_range_type;
// コンテナー全体の操作
enumerable_thread_specific();
enumerable_thread_specific(
const enumerable_thread_specific &other
);
template<typename U, typename Alloc,
ets_key_usage_type Cachetype>
enumerable_thread_specific(
const enumerable_thread_specific<U, Alloc,
Cachetype>& other );
template <typename Finit>
enumerable_thread_specific( Finit finit );
enumerable_thread_specific(const T &exemplar);
~enumerable_thread_specific();
enumerable_thread_specific&
operator=(const enumerable_thread_specific& other);
template<typename U, typename Alloc,
ets_key_usage_type Cachetype>
enumerable_thread_specific&
operator=(
const enumerable_thread_specific<U, Alloc, Cachetype>&
other
);
void clear();
// 並列操作
reference local();
reference local(bool& existis);
size_type size() const;
bool empty() const;
// 組み合わせ
template<typename FCombine> T combine(FCombine fcombine);
template<typename Func> void combine_each(Func f);
// 並列反復
range_type range( size_t grainsize=1 );
const_range_type range( size_t grainsize=1 ) const;
// イテレーター
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
};
}