OpenMPはC++でも利用できるものの、ループやブロックを対象として並列化を行うため、C++で利用する場合には扱いにくい場合もある。そこで、C++で並列処理を実装する場合に検討したいのがThreading Building Blocks(TBB)である。
TBBはC++のテンプレート機構を活用した並列処理実装のためのテンプレートライブラリで、処理を分割して実行するアルゴリズムや並列処理を行うデータを格納するためのコンテナ、メモリ管理機構、排他・同期処理機構、タスクスケジューラなどから構成されている。TBBはループを置き換えるのではなく、処理もしくはデータを分割して実行するという観点から設計されているのも特徴である。
TBBはインテルが開発し、登場した当初は商用製品としてリリースされていたが、2007年にオープンソース化され(ライセンスはGPL2)、現在は無償で入手および利用が可能だ。また、インテル コンパイラーやParallel Studioなどには非フリーのソフトウェアからでも利用できる商用版が付属している。
である。
TBBを利用する場合、まず分割して処理するデータにアクセスするためのイテレータを定義し、そのイテレータと実行する処理となる関数オブジェクトをTBBが用意する並列処理アルゴリズムに与えて分割実行させる、という形になる。データを分割するだけでなく、処理を分割してパイプライン処理させることも可能だ。
データにアクセスするためのイテレータはTBBのテンプレートクラスとしていくつかが用意されているほか、利用するデータに応じてオリジナルのイテレータを実装することもできる。並列処理アルゴリズムとしては、表5のようなものに加え、パイプライン処理を実装するためのクラス「pipeline」が用意されている。
| アルゴリズム(関数)名 | 説明 |
|---|---|
| parallel_for() | 指定された範囲に対して処理を並列に実行する |
| parallel_reduce() | 指定された範囲に対して処理を実行し、それぞれの実行結果に対して和や積、最大/最小といった集計操作を行うリダクション処理を実行する |
| parallel_scan() | 指定された範囲に対して並列スキャン処理を実行する |
| parallel_while() | 実行前にはループ回数が分からないループ処理を並列に実行する |
| parallel_sort() | 並列ソートを実行する |
たとえばTBBを使ってループを並列化する場合、次のようにする。
/* 必要なヘッダーファイルをインポート */
#include "tbb/task_scheduler_init.h"
#include "tbb/parallel_for.h"
#include "tbb/blocked_range.h"
/* tbb名前空間をインポート */
using namespace tbb;
:
:
class ParallelProc {
public:
/*
* operator(): 並列実行する処理を定義する関数オブジェクト
* const blocked_rangesize_t r: 処理する範囲
*/
void operator() (const blocked_rangeint r) const {
int i;
for (i = r.begin(); i != r.end(); i++) {
/* 並列化したい処理をここに記述
}
}
}
void hogehoge() {
/* 1スレッドで実行する処理 /*
:
:
/* 1スレッドで実行する処理ここまで /*
/* TBBのスケジューラを初期化 */
task_scheduler_init init;
/* 並列処理を行うデータ範囲を用意 */
blocked_range2dint range(0, n, 1000)
/* 処理を行う関数オブジェクトを作成 */
ParallelProc proc_obj;
/* データ範囲と関数オブジェクトを与えて並列実行 */
parallel_for(range, proc_obj);
/* 1スレッドで実行する処理 /*
:
:
}
TBBを利用した並列化は一見OpenMPによる並列化よりも複雑に見えるが、実行する処理をクラスとして記述するため汎用性が高いのが特徴である。また、ここでは1次元のループを並列化する例を挙げているが、2次元、3次元のループについてもその構造を保ったままに並列化が可能だ。